local Player = import(".Player")
local Skill = import(".Skill")
local Item = import(".Item")
local Equip = import(".Equip")
local Rune = import(".Rune")
local NPC = import(".NPC")
local Friend = import(".Friend")
local Mount = import(".Mount")
local Tool = import(".Tool")
local Talent = import(".Talent")
local Fame = import(".Fame")
local MapBuff = import(".MapBuff")
local Achievement = import(".Achievement")
local FormulaId = import(".FormulaId")
local KeyValue = import(".KeyValue")
local Setting = import(".Setting")
local Badge = import(".Badge")
local Bag = import(".Bag")
local LocalStorage = import(".LocalStorage")

local Clothes = import(".Clothes")
local Formation = import(".Formation")
local ActiveReward = import(".ActiveReward")
local Task = import(".Task")
local MountSoul = import(".MountSoul")
local PartnerSoul = import(".PartnerSoul")
local EquipGrid = import(".EquipGrid")
local CoreProp = import(".CoreProp")
local MsdkData = import(".MsdkData")
local RedPoint = import(".RedPoint")
local PartnersData = import(".PartnersData")
local CSGuildWarData = import(".CSGuildWarData")
local CSEliteMatch = import(".CSEliteMatch")
local SuperRankData = import(".SuperRankData")

local BattleInfoNormal = require("app.world.models.vo.BattleInfoNormal")

local UserData = class("UserData")

local FileUtils = cc.FileUtils:getInstance()
local table_insert = table.insert
local handle_index = 0

local COIN_WALLET_NAMES = {
	[99] = "gold", [98] = "coin", [97] = "exp", [96] = "power", [95] = "honor",
	[94] = "presentCoin", [93] = "serveMedal", [92] = "magicDust", [91] = "eventPoint",
	[89] = "jewelChip", [88] = "", [87] = "bindCoin", [86] = "talentPoint", [85] = "skillPoint",
	[84] = "starPoint", [83] = "", [82] = "partnerExp",[110] = "roseGold", [115] = "magicCrystal",[121] = "dungeonPoint",
	[122] = "dungeonLuckBox", [123] = "eventLuckBox", [124] = "arenaLuckBox"
}

function UserData:ctor()
	self._coinWallets = {} -- 资源钱包
	self._boxCacheInfo = {} -- 地城/活动宝箱缓存信息initSkillConf

	self.player = Player.new()
	self.player:onChanged(function(name,old,new)
		if name == "level" then
			--判断是否有可获得新技能
			UD.redPoint:checkStateByKey(RedPointConstant.Skill_Skill)
			self:calUserdataAttr() -- 属性数据过期，重算
			EM:notify("onPlayerLevelChange", new)
		elseif name == "skillChooseID" then
			self:calUserdataAttr() -- 属性数据过期，重算
		elseif name == "recharge" then
			EM:notify("onPlayerRechargeChange", new)
		elseif name == "combatPower" then
			EM:notify("onCombatPowerChange", new)
		end
	end)
	self.bag = Bag.new()
	self.setting = Setting.new()
	self.badge = Badge.new()
	self.localStorage = LocalStorage.new()
	self:clear()

	-- 该uid和player里面的uid一样
	self.uid = nil
	self.dirty = false
	self.file = nil

	self._isInit = false -- 是否初始化过

	--cur zone name
	self.zoneName = ""
	self._listenerDict = {}
	self._userListerner = nil

	self._clothes = {}  -- 已激活时装列表 不仅仅是ID了

	self.minEquipStrengthLv = 0 -- 人物强化等级
	self._equipGrids = {} --玩家身上的装备格子信息  以location为KEY EquipGrid为Value

	self._loginClothesEndFlag = false -- 时装初始化完成?
	self._newGotRenownList = {}  -- 新改变的声望ID
	self._newCharmNum = false -- 幸运星数量是否增多
	--主线任务分支
	self._taskBranchs = {}
	-- 屏蔽头像
	self.isHeadShield = false
end

function UserData:clear()
	self._coinWallets = {}
	self._boxCacheInfo = {} -- 地城/活动宝箱缓存信息
	self.equips={}

	self._clothes = {}  -- 已激活时装ID列表

	self._loginClothesEndFlag = false

	self.minEquipStrengthLv = 0
	self._equipGrids = {}

	self.tasks = {}
	self.quests = {}
	self.npcResourcePoints = {}
	self.friends = {}
	self.blacks = {}
	self.mounts = {}
    self.tools={}
	self.talents = {}
    self.skills = {}
    self.runes = {}
	self.fames = {}
	self.mapBuffs = {}
	self._mapBuffUIds = {}
	self.bag:clear()
	self.achievements = {}
	self.formulaIds = {}
	self.kvStores = {}
	self.player:clear()
	self.setting:clear()
	self.badge:clear()
	self.localStorage:clear()
    self.partners = {}
    self.skillChooses = {}
	self.activatedMounts={}
	self.mountHomeNum = 0
    self.activatedMountNum = 0
    self.lifeSkills = {}
    self.mountSouls = {}
    self.partnerSouls = {}

    -- 队伍自动申请的targetId列表
    self.autoJoinList = {}

    -- 已完成支线任务ids
    self.finishedSideTaskIds = {}

    -- 副本剩余次数dict
    self.dungeonTimesDict = {}

	-- 服务器控制关闭的玩法
	self.closedFeatures = {}

    self.luckboxId = 0 -- 副本宝箱id，用来开启副本结束未开过的宝箱

    -- self._localItems = {}	--本地存储道具信息（isNew）

	self._luckBoxOpendTimesList = {} -- 地城、竞技场、活动本宝箱开启过次数

	self._newGotRenownList = {}
	self._newCharmNum = false

	self:clearBattle()

	self.coreProp = CoreProp.new()
	self.msdkData = MsdkData.new()
	self.redPoint = RedPoint.new()
	self:clearUserdataAttr()

	-- 随从
	
	self.partnersData = PartnersData.new()
	-- 跨服工会战
	self.csGuildWarData = CSGuildWarData.new()
	-- 跨服精英赛
	self.csEliteMatch = CSEliteMatch.new()
	-- 超级排行
	self.superRankData = SuperRankData.new()
end

function UserData:load(file)
	if not file then
		return
	end
	-- 兼容 老设置
	local oldSettingPath = file..".ud"
	if FileUtils:isFileExist(oldSettingPath) then
		local f = io.open(oldSettingPath , "rb")
		if f then
			local buffer = f:read "*a"
			if buffer then
				local decode,err = protobuf.decode("shared.LocalUserData",buffer)
				if decode then
					self:localRead(decode)
				else
					print("===>LocalUserData:load error",err)
				end
			end
			f:close()
		end
		FileUtils:removeFile(oldSettingPath)
		self:save()
	end
	-- 使用 json
	local newSettingPath = file..".json"
	if FileUtils:isFileExist(newSettingPath) then
		local content = cc.FileUtils:getInstance():getStringFromFile(newSettingPath)
		local data = json.decode(content)
		if data then
			self:localRead(data)
		end
	end
    self.file = newSettingPath
end

function UserData:save()
	if not self.file then
		return false
	end
	local t = {}
	self:write(t)
	local jsonStr = json.encode(t)
	if jsonStr then
		io.writefile(self.file, jsonStr)
	end
	return true
end

local check = function(v,d)
	if v then
		return v
	else
		return d
	end
end

function UserData:initZoneData(uid, zoneId, zoneName, zoneUTC)
	self.uid = uid
	self.zoneId = zoneId
	self.zoneName = zoneName
	self.zoneUTC = zoneUTC

	local filePath = app:getStorePath().."/user_"..uid.."_"..zoneId
	UD:load(filePath)

    UD.msdkData:requestMsdkBusiness()
end

function UserData:initBattle(msg)
	-- print("session battleId", msg.battleId, type(msg.battleId), #msg.battleId)
	-- print("session battleUrl", msg.battleUrl, type(msg.battleUrl))
	-- print("session battleAuthCode", msg.battleAuthCode, type(msg.battleAuthCode))
	-- print("session formationID", msg.formationID, type(msg.formationID))
	-- print("session battleMapID", msg.battleMapID, type(msg.battleMapID))

	if msg.battleId and #msg.battleId > 0 then
		self.battleId = msg.battleId
		self.battleUrl = msg.battleUrl
		self.battleAuthCode = msg.battleAuthCode
		self.formationId = msg.formationID
		self.battleMapID = msg.battleMapID
		self.isUsingArenaAvatar = msg.isUsingArenaAvatar
	end
end

function UserData:clearBattle()
	self.battleId = nil
	self.battleUrl = nil
	self.battleAuthCode = nil
	self.formationId = nil
	self.battleMapID = nil
	self.isUsingArenaAvatar = nil
end

-- 当前服务器在战斗状态中
function UserData:hasBattle(mapId)
	local hasBattle = false
	if self.battleId and UD.battleUrl and string.len(UD.battleUrl) > 0 then
		hasBattle = true
	end

	-- 1.有地图要求 2.传入了地图id
	if hasBattle and self.battleMapID > 0 and mapId then
		hasBattle = self.battleMapID == mapId
	end

	-- print("UserData:hasBattle", hasBattle, mapId)

	if hasBattle then
		local enterBattleInfo = BattleInfoNormal.new({
			id = self.battleId,
			url = self.battleUrl,
			authCode = self.battleAuthCode,
			formationId = self.formationId,
			mapId = mapId,
			isUsingArenaAvatar = self.isUsingArenaAvatar,
		})
		return true, enterBattleInfo
	else
		return false
	end
end

-- 是否初始化过
function UserData:isInit()
	return self._isInit
end

function UserData:read(value)
	-- 是否init
	self._isInit = true

	self:initUserdataAttr() -- 初始化人物属性列表

	self.player:clear()
	if value.player then
		self.player:read(value.player, false)
		self.player:setHasInit()
	end
	--dump(self.player, "UserData.player")

	self.isHeadShield = value.isHeadShield or false -- 屏蔽头像

	local equips = value.equips
	self.equips={}
	if equips then
		for i=1,#equips do
			local equip = Equip.new()
			equip:read(equips[i])
			equip:setWear(true)
			if equip:isValid() then
	        	self.equips[equip.uid]=equip
	        else
	        	release_print("UserData:read equip not valid",equip.tid)
	    	end
		end
	end

	-- 更新装备格子强化等级信息
	self._equipGrids = {} --以location为KEY EquipGrid为Value
	local grids = value.grids
    local minLevel = 9999  -- 可以强化的部位的最小强化等级
	if grids then
		for i=1,#grids do
			local equipGrid = EquipGrid.new()
			equipGrid:read(grids[i])
			equipGrid:setEquip(self:getEquip(grids[i].UUID))
			self._equipGrids[equipGrid:getLocation()] = equipGrid
            for _, v in pairs(Enums.GridCanStrengthen) do
                if grids[i].location == v then
                    minLevel = math.min(minLevel, equipGrid:getStrengthLevel())
                    break
                end
            end
		end
	end
	self.minEquipStrengthLv = minLevel -- 更新人物强化等级

	local mountSouls = value.mountSouls
	self.mountSouls = {}
	if mountSouls then
		for i=1,#mountSouls do
			local mountSoul = MountSoul.new()
			mountSoul:read(mountSouls[i])
			if mountSoul:isValid() then
	        	self.mountSouls[mountSoul.id] = mountSoul
	        else
	        	release_print("UserData:read mountSoul not valid", mountSoul.id)
	    	end
		end
	end

	local partnerSouls = value.partnerSouls
	self.partnerSouls = {}
	if partnerSouls then
		for i=1,#partnerSouls do
			local partnerSoul = PartnerSoul.new()
			partnerSoul:read(partnerSouls[i])
			if partnerSoul:isValid() then
	        	self.partnerSouls[partnerSoul.id] = partnerSoul
	        else
	        	release_print("UserData:read partnerSoul not valid", partnerSoul.id)
	    	end
		end
	end

	local tasks = value.tasks
	self.tasks = {}
	if tasks then
		for i = 1,#tasks do
			local task = Task.new()
			task:read(tasks[i])
			self.tasks[task.id] = task
			self:setCurTask(task)
			if task:isBounty() then
				BattleManager:countDarkThunderBattlePoints(task, "insert")
			end
		end
	end

	-- 目前仅仅用于传递所有资源点信息
	local npcResourcePoints = value.pickPoints
	self.npcResourcePoints={}
	if npcResourcePoints then
		for i=1,#npcResourcePoints do
			local npcResourcePoint = NPC.new()
			npcResourcePoint:read(npcResourcePoints[i])
			self.npcResourcePoints[npcResourcePoint.id]=npcResourcePoint
		end
	end

	local friends = value.friends
	self.friends={}
	if friends then
		for i=1,#friends do
			local friend = Friend.new(friends[i], Enums.FriendType.friend)
			self.friends[friend.uid]=friend
		end
	end

	local blacks = value.blacklist
	self.blacks={}
	if blacks then
		for i=1,#blacks do
			local black = Friend.new(blacks[i], Enums.FriendType.black)
			self.blacks[black.uid]=black
		end
	end

    local mounts = value.mounts
	self.mounts={}
	if mounts then
	    for i = 1,#mounts do
	        local mount = Mount.new()
	        mount:read(mounts[i])
	        mount:setHave(true)
	        self.mounts[mount.uid] = mount
		end
	end

	local skillChooses = value.skillChooses
	self.skillChooses = {}
	if skillChooses then
		for _,v in ipairs(skillChooses) do
			self.skillChooses[v.id] = v
		end
	end

	self:initSkillConf()
	local talents = value.talents
	self.talents={}
	if talents then
		for i = 1,#talents do
			local talentId = talents[i].uid
			local talent = self:getTalent(talentId)
			talent:setActive(true)
			self.talents[talentId] = talent
		end
	end

	-- 符文相关数据
	local runes = value.runes
	self.runes = {}
	if runes then
		for i = 1, #runes do
			local value = runes[i]
			local rune = self:getRune(value.id)
			if rune then
				rune:read(value)
				self.runes[ rune:getId() ] = rune
			end
		end
	end

	local skills = value.skills
	self.skills={}
	if skills then
		for i = 1,#skills do
			local skill = Skill.new()
			skill:read(skills[i])
			skill:setLearned()
			self.skills[skill.id] = skill
		end
	end


	local fames = value.fames
	self.fames={}
	if fames then
		for i = 1,#fames do
			local fame = Fame.new()
			fame:read(fames[i])
			if fame:isValid() then
				self.fames[tostring(fame.uid)] = fame
			else
				print("UserData:read fame not valid",fame.uid)
			end
		end
	end

	local mapBuffs = value.mapBuffs
	self.mapBuffs={}
	self._mapBuffUIds = {}
	if mapBuffs then
		for i = 1,#mapBuffs do
			local mapBuff = MapBuff.new()
			mapBuff:read(mapBuffs[i])
			self.mapBuffs[mapBuff.uid] = mapBuff
			table_insert(self._mapBuffUIds,mapBuff.uid)
		end
	end

	-- local newsItems = self.bag:getItemIsNews()
	-- if #newsItems == 0 then
	-- 	newsItems = self._localItems
	-- end
	self.bag:clear()
	if value.bag then
		self.bag:read(value.bag)
	end
	-- self.bag:setItemIsNews(newsItems)

	-- local achievements = value.achievements
	-- self.achievements={}
	-- if achievements then
	-- 	for i = 1,#achievements do
	-- 		local achievement = Achievement.new()
	-- 		achievement:read(achievements[i])
	-- 		self.achievements[tostring(achievement.uid)] = achievement
	-- 	end
	-- end

	local formulaIds = value.formulaIds
    --存本地new
	self.formulaIds={}
	if formulaIds then
		for i = 1,#formulaIds do
			local formulaId = FormulaId.new()
			formulaId:read(formulaIds[i])
			self.formulaIds[formulaId.id] = formulaId
		end
	end

	-- 服务器让删掉了
	-- local tools = value.tools
	-- self.tools={}
	-- if tools then
	-- 	for i=1,#tools do
	-- 		local tool = Tool.new()
	-- 		tool:read(tools[i])
	--         self.tools[tool.tid]=tool
	-- 	end
	-- end

	local kvStores = value.kvStores
	self.kvStores.tutorial = {}
	local tutorial = kvStores.tutorial
	if tutorial then
		local items = tutorial.items or {}
		for i,v in ipairs(items) do
			local keyValue = KeyValue.new()
			keyValue:read(v)
			self.kvStores.tutorial[v.key] = keyValue
		end
	end
	self.kvStores.generic = {}
	local generic = kvStores.generic
	if generic then
		local items = generic.items or {}
		for i,v in ipairs(items) do
			local keyValue = KeyValue.new()
			keyValue:read(v)
			self.kvStores.generic[v.key] = keyValue
		end
	end

	self.partnersData:updatePartners(value.partners)

	local activatedMounts = value.activatedMounts
	self.activatedMounts = {}
	self.activatedMountNum = 0
	if activatedMounts then
		for i = 1,#activatedMounts do
			local mount = Mount.new()
			mount:read(activatedMounts[i].mount)
			mount:setIndex(activatedMounts[i].index+1)
            mount:setHave(true)
			self.activatedMounts[mount:getUid()] = mount
		end
		self.activatedMountNum = #activatedMounts
	end

	local mountHomeNum = rawget(value, "mountHomeNum")
	if mountHomeNum and mountHomeNum > 0 then
		self.mountHomeNum = mountHomeNum
	end

	-- TODO lifeSkills里面的对象是proto对象，可以优化一下建立一个结构
	local lifeSkills = value.lifeSkills
	self.lifeSkills = {}
	if lifeSkills then
		for i,v in ipairs(lifeSkills) do
			self.lifeSkills[v.uid] = v
		end
	end

	-- 地下城经验卡
	self._userExpCard = ActiveReward.new()
	self._userExpCard:read(value.userExpCard)

	local wallets = value.wallets
	-- dump( wallets, " ------------------>>>>>. wallets " )
	self._coinWallets = {}
	if wallets then
		for i,v in ipairs(wallets) do
			self._coinWallets[v.key] = v.value
		end
	end

	local luckboxOpenTimes = value.luckboxOpenTimes
	self._luckBoxOpendTimesList = {}
	if luckboxOpenTimes then
		for i,v in ipairs( luckboxOpenTimes ) do
			self._luckBoxOpendTimesList[ v.typ ] = v
		end
	end
	-- dump(self._luckBoxOpendTimesList, "-------------------->>>>._luckBoxOpendTimesList")
	-- 副本宝箱id(不要了，先屏蔽掉)
	--self.luckboxId = value.luckboxId

	-- 队伍自动申请的targetId列表
	local autoJoinList = value.autoJoinList
	self.autoJoinList = {}
	if autoJoinList then
		for i,v in ipairs(autoJoinList) do
			self.autoJoinList[#self.autoJoinList + 1] = v
		end
	end

	-- 完成的支线任务ids
	local finishedSideTaskIds = value.finishedSideTaskIds
	self.finishedSideTaskIds = {}
	if finishedSideTaskIds then
		for i,v in ipairs(finishedSideTaskIds) do
			self.finishedSideTaskIds[#self.finishedSideTaskIds + 1] = v
		end
	end

	-- 副本次数
	local remainTimes = value.DungeonRemainTimes
	self.dungeonTimesDict = {}
	if remainTimes then
		for i,v in ipairs(remainTimes) do
			self.dungeonTimesDict[v.ID] = v
		end
	end

	-- 服务器控制关闭的玩法
	local closedFeatures = value.ClosedFeatures
	self.closedFeatures = {}
	if closedFeatures then
		for i, v in ipairs(closedFeatures) do
			local id = tonumber(v)
			self.closedFeatures[id] = id
		end
	end

	----已激活时装--------
	self._clothes = {}
	for k,v in ipairs(value.fashions) do
		local tmpClothes = Clothes.new()
		tmpClothes:read({tid = v.id})
		self._clothes[v.id] = tmpClothes
	end

	----superTilte----
	self:onSpReward(value.spRewards,false)


	self.grayBattleInfo = value.grayBattleInfo

	--core prop
	if value.corePropData then
		self.coreProp:updateData(value.corePropData)
	end

	self:initGrayBattleNpcData()

	self:initShownProp()
	self:calUserdataAttr()

	-- -- 获取秘境副本
	-- SecretManager:init()
	-- -- 初始化成就
	-- AchievementManager:reqAchievements()

	app:sendMsg("JewelModel", "refreshRedPoint")
end

function UserData:localRead(value)
	local setting = value.setting
	if setting then
		self.setting:clear()
		self.setting:read(setting)
	end

	-- local badges = value.badges
	-- if badges and #badges>0 then
	-- 	self.badge:clear()
	-- 	self.badge:read(badges)
	-- end

	-- local items = value.items
	-- self._localItems = {}
	-- if items and #items > 0 then
	-- 	self._localItems = items
	-- end

	local localStorage = value.localStorage
	if localStorage then
		self.localStorage:clear()
		self.localStorage:read(localStorage)
	end
end

function UserData:write(t)
	t.setting = {}
	self.setting:write(t.setting)

	-- t.badges = {}
	-- self.badge:write(t.badges)

	-- t.items = {}
	-- self.bag:write(t.items)

	t.localStorage = {}
	self.localStorage:write(t.localStorage)
end

function UserData:dump()
	-- TODO csg ／ UserData dump

end

function UserData:apply(oper,dispatchEvent,ignoreNew)
	local eventName = nil
	local eventArgs = {}

	--dump(oper, "UD.apply")

	if oper.player then
		local preCharmNumTemp = self.player.charm.num

		self.player:apply(oper.player,dispatchEvent)
		eventName="player"
		eventArgs={self.player}

		local curCharmNumTemp = self.player.charm.num
		if preCharmNumTemp and curCharmNumTemp and curCharmNumTemp > preCharmNumTemp then
			self:setCharmNumNew(true)
		end
	elseif oper.wallets and #oper.wallets > 0 then
		local values = oper.wallets
		-- dump(values, "-------------->>>>>>update walltes")
		 -- 缓存地城/竞技/活动宝箱和点数的变化
		for kCache,vCache in pairs(values) do
			local keyCache = vCache.key
			local newCache = vCache.value
			local oldCache = self:getDaibiValue(keyCache)
			if keyCache == Enums.lootType.dungeonLuckBox 
				or keyCache == Enums.lootType.eventLuckBox
				or keyCache == Enums.lootType.arenaLuckBox then
				if newCache >= oldCache then
					self:setLuckBoxCache(keyCache, oldCache) 
				end
			elseif keyCache == Enums.lootType.dungeonPoint
				or keyCache == Enums.lootType.eventPoint
				or keyCache == Enums.lootType.starCount then
				self:setLuckBoxCache(keyCache, oldCache)
			end
		end

		for k,v in pairs( values ) do
			local key = v.key
			local new = v.value
			local old = self._coinWallets[key] or 0
			self._coinWallets[ key ] = new

			-- 赠送钻石算在钻石数量里面，共用钻石的改变事件
			if key == Enums.lootType.presentCoin then
				key = Enums.lootType.coin
				local coin = self._coinWallets[Enums.lootType.coin] or 0
				old = old + coin
				new = new + coin
			elseif key == Enums.lootType.coin then
				local presentCoin = self._coinWallets[Enums.lootType.presentCoin] or 0
				old = old + presentCoin
				new = new + presentCoin
			end

			eventName = COIN_WALLET_NAMES[ key ]
			if dispatchEvent and eventName and old ~= new then
				eventArgs = { eventName, old, new, key }
				--dump( eventArgs, " ------------>>>> UserData:apply wallets " .. eventName )
				self:dispatchChange("wallet",unpack(eventArgs))
			end
		end
		-- dump( self._coinWallets, " ------------------>>>>>update wallets " )
		dispatchEvent = false -- 屏蔽掉后面统一分发消息的逻辑
	elseif oper.equip then
		local value = oper.equip
		local uid = value.uid
		local equip = self.equips[uid]
		local pos = nil
		if oper.opt=="insert" or oper.opt=="update" then
			if not equip then
				equip = Equip.new()
				equip:setWear(true)
			end
			equip:read(value)
			pos = equip:getPos()
			self.equips[uid] = equip
		elseif oper.opt=="delete" then
			pos = equip:getPos()
			self.equips[uid] = nil
		end
		eventName="equip"
		eventArgs={uid,equip,oper.opt,pos}

		-- TODO 这个应该服务器做，暂时修改grid的UUID，并发出更新
		if oper.opt ~= "update" then
			local equipGrid = self:getEquipGridByPos(pos)
			local grid = {}
			equipGrid:write(grid)
			grid.UUID = oper.opt=="insert" and uid or 0
			self:apply({grid=grid, opt="update"}, true)
		end

		self:calUserdataAttr() -- 属性数据过期，重算
	elseif oper.taskBranchs and #oper.taskBranchs > 0 then
		-- 这里opt只有 update，全量更新
		self._taskBranchs = {}
		local values = oper.taskBranchs
		for k, v in pairs(values) do
			self._taskBranchs[v.prevTaskID] = v.nextTaskID
		end 
	elseif oper.tasks and #oper.tasks > 0 then
		local values = oper.tasks
		local tasks = {}
		for i,value in ipairs(values) do
			local id = value.id
			local task = (self.tasks[id] == nil) and Task.new() or self.tasks[id]
			task:read(value)
			tasks[id] = task
			if oper.opt == "insert" or oper.opt == "update" then
				self.tasks[id] = task
	            self:setCurTask(task)
			elseif oper.opt=="delete" then
				task = nil
				self.tasks[id] = nil
			end
		end

		eventName = "task"
		eventArgs = {tasks,oper.opt}
	-- elseif oper.npc then
	-- 	local value = oper.npc
	-- 	local uid = value.uid
	-- 	local npc = self.npcResourcePoints[uid]
	-- 	if oper.opt=="insert" or oper.opt=="update" then
 --            if not npc then
	-- 		    npc = NPC.new()
 --            end
 --            npc:read(value)
 --            self.npcResourcePoints[uid]=npc
	-- 	elseif oper.opt=="delete" then
	-- 		npc=nil
	-- 		self.npcResourcePoints[uid] = nil
	-- 	end
	-- 	eventName="resoucePointNpcUpdate"
	-- 	eventArgs={uid,npc,oper.opt}
	elseif oper.friend then
		local value = oper.friend
		local uid = value.userBaseInfo.uid
		local friend = self.friends[uid]
		if oper.opt=="insert" or oper.opt=="update" then
            if not friend then
    		    friend = Friend.new(nil, Enums.FriendType.friend)
	    	    self.friends[uid]=friend
            end
            friend:read(value)
		elseif oper.opt=="delete" then
			self.friends[uid] = nil
			friend=nil
		end
		eventName="friend"
		eventArgs={uid,friend,oper.opt}
	elseif oper.blacklist then
		local value = oper.blacklist
		local uid = value.userBaseInfo.uid
		local black = self.blacks[uid]
		if oper.opt=="insert" or oper.opt=="update" then
            if not black then
    			black = Friend.new(nil, Enums.FriendType.black)
			    self.blacks[uid]=black
            end
            black:read(value)
		elseif oper.opt=="delete" then
			self.blacks[uid] = nil
			black=nil
		end
		eventName="black"
		eventArgs={uid,black,oper.opt}
    elseif oper.mount then
        local value = oper.mount
        local uid = value.uid
        local mount = self.mounts[uid]
        if oper.opt=="insert" or oper.opt=="update" then
            if not mount then
                mount = Mount.new()
                mount:setHave(true)
				if not ignoreNew then
					mount:setIsNewGet(true)
				end
            end
            mount:read(value)
            self.mounts[uid]=mount

            if oper.opt=="insert" then
	            -- 新的坐骑，必定会有红点
            	self.redPoint:setStateByKey(RedPointConstant.Mount_Ride, true)
            	self.redPoint:setStateByKey(Constant.FUNC_TYPE_MOUNT_PIT, true)
            else
            	-- 坐骑更新，重新计算红点
            	self.redPoint:checkStateByKey(RedPointConstant.Mount_Ride)
            	self.redPoint:checkStateByKey(Constant.FUNC_TYPE_MOUNT_PIT)
            end
        elseif oper.opt=="delete" then
            self.mounts[uid] = nil
            mount=nil
        end
        eventName="mount"
		eventArgs={uid,mount,oper.opt}
    elseif oper.mountSoul then
        local value = oper.mountSoul
        local id = value.id
        local mountSoul = self.mountSouls[id]
        local oldNum = mountSoul and mountSoul:getAmount() or 0
        local newNum = oldNum
        if oper.opt=="insert" or oper.opt=="update" then
            if not mountSoul then
                mountSoul = MountSoul.new()
            end
            newNum = value.num
            mountSoul:read(value)
            self.mountSouls[id]=mountSoul
        elseif oper.opt=="delete" then
            self.mountSouls[id] = nil
            newNum = 0
        end

        self.redPoint:checkStateByKey(RedPointConstant.Mount_Ride)
        self.redPoint:checkStateByKey(Constant.FUNC_TYPE_MOUNT_PIT)

        eventName="mountSoul"
		eventArgs={id, mountSoul, newNum-oldNum, oper.opt}
	elseif oper.partnerSoul then
        local value = oper.partnerSoul
        local id = value.id
        local partnerSoul = self.partnerSouls[id]
        local oldNum = partnerSoul and partnerSoul:getAmount() or 0
        local newNum = oldNum
        if oper.opt=="insert" or oper.opt=="update" then
            if not partnerSoul then
                partnerSoul = PartnerSoul.new()
            end
            newNum = value.num
            partnerSoul:read(value)
            self.partnerSouls[id]=partnerSoul
        elseif oper.opt=="delete" then
            self.partnerSouls[id] = nil
            newNum = 0
		end
		UD:updateWelfareNewPoint(Constant.FUNC_TYPE_MERCENARY, self.partnersData:hasPartnerCanLvOrCanActive())
        eventName="partnerSoul"
		eventArgs={id, partnerSoul, newNum-oldNum, oper.opt}

	elseif oper.talent then
		local value = oper.talent
		local uid = value.uid
		local talent = self:getTalent(uid)
		if oper.opt=="insert" or oper.opt=="update" then
			talent:setActive(true)
            self.talents[uid]=talent
		elseif oper.opt=="delete" then
			talent:setActive(false)
			self.talents[uid] = nil
			talent=nil
		end
		eventName="talent"
		eventArgs={uid,talent}
		self:calUserdataAttr() -- 属性数据过期，重算
	elseif oper.skill then
		local value = oper.skill
		local uid = value.uid
		local skill = self.skills[uid]
		if oper.opt=="insert" or oper.opt=="update" then
            if not skill then
			    skill = Skill.new()
			end
			skill:read(value)
			skill:setLearned()
            self.skills[uid]=skill
		elseif oper.opt=="delete" then
			self.skills[uid] = nil
			skill=nil
		end
		eventName="skill"
		eventArgs={uid,skill}
	elseif oper.fame then
		local value = oper.fame
		local uid = tostring(value.uid)
		local fame = self.fames[uid]
		if oper.opt=="insert" or oper.opt=="update" then
            if not fame then
			    fame = Fame.new()
			end
			fame:read(value)
            self.fames[uid]=fame
		elseif oper.opt=="delete" then
			self.fames[uid] = nil
			fame=nil
		end
		eventName="fame"
		eventArgs={uid,fame}

		----------->>>> 保存发生改变的声望ID
		if fame and oper.opt=="update" then
			table.insert( self._newGotRenownList, fame.uid )
			self.redPoint:checkStateByKey(Constant.FUNC_TYPE_PACK_PRESTIGE)
		end
	elseif oper.mapBuff then
		local value = oper.mapBuff
		local uid = value.uid
		local mapBuff = self.mapBuffs[uid]
		if oper.opt=="insert" or oper.opt=="update" then
            if not mapBuff then
			    mapBuff = MapBuff.new()
			else
				--将其从self._mapBuffUIds中移除
				for k, v in ipairs(self._mapBuffUIds) do
					if v == uid then
						table.remove(self._mapBuffUIds,k)
						break
					end
				end
		    end
		    mapBuff:read(value)
		    table_insert(self._mapBuffUIds,1,uid)
			self.mapBuffs[mapBuff.uid]=mapBuff
		elseif oper.opt=="delete" then
			--将其从self._mapBuffUIds中移除
			for k, v in ipairs(self._mapBuffUIds) do
				if v == uid then
					table.remove(self._mapBuffUIds,k)
					break
				end
			end

			self.mapBuffs[uid] = nil
			
			mapBuff=nil
		end
		eventName="mapBuff"
		eventArgs={uid,mapBuff}
		self:calUserdataAttr() -- mapBuff数据过期，重算
	elseif oper.Bag then
		if oper.Bag.cells and 0 < #oper.Bag.cells then -- 背包物品变化
			local item,amountGot = self.bag:apply(oper,dispatchEvent,ignoreNew)
			if oper.opt == "delete" then
				if item.isNew then
					item:setIsNewGet(false)
					self.redPoint:checkStateByKey(RedPointConstant.Bag_NewItem)
				end
			else
				if item.isNew then
					self.redPoint:setStateByKey(RedPointConstant.Bag_NewItem, true)
				end
			end

			eventName="bag"
			eventArgs={}

			-- 坐骑升星材料，刷新坐骑红点
			if item:getItemType() == Enums.ItemType.mountStar then
				self.redPoint:checkStateByKey(Constant.FUNC_TYPE_MOUNT_PIT)
			end

		else -- 背包等级变化
			self.bag:setBagLv( oper.Bag.bagID )
			eventName="bagExtend"
			eventArgs={}
		end
	elseif oper.achievements and #oper.achievements > 0 then		
		eventName="achievement_task"
		eventArgs={oper.achievements}
	elseif oper.formulaId then
		local value = oper.formulaId
		local id = value.id
		local formulaId = self.formulaIds[id]
		if oper.opt=="insert" or oper.opt=="update" then
            if not formulaId then
            	formulaId=FormulaId.new()
            end
			formulaId:read(value)
            formulaId:setIsNewGet(true)
			self.formulaIds[id] = formulaId
			UD.redPoint:setStateByKey(Constant.FUNC_TYPE_COMPOUND, true)
		elseif oper.opt=="delete" then
			self.formulaIds[id] = nil
			formulaId=nil
		end
		eventName="formulaId"
		eventArgs={id,formulaId}
	elseif oper.runes and 0 < #oper.runes then
		local values = oper.runes
		for i, value in ipairs( values ) do
			local id = value.id
			local rune = self.runes[id]
			if oper.opt == "insert" or oper.opt == "update" then
				if not rune then
					rune = self:getRune(id)
					rune:setIsNewGet(true)
				end
				rune:read(value)
				self.runes[id] = rune
				self:_setRunePlaceDirtyFlag(rune:getEquipPlace())
			elseif oper.opt == "delete" then
				rune:setIsNewGet(false)
				rune:clearEquipState()
				self.runes[id] = nil
			end
		end
		eventName = "runesChanged"
		eventArgs = { values, oper.opt }

		if oper.opt ~= "delete" then
			UD.redPoint:checkStateByKey(RedPointConstant.Skill_Rune)
		end

	elseif oper.partner  then
		self.partnersData:updateByOper(oper.opt, oper.partner)
		-- local value = oper.partner
		-- if oper.opt=="insert" or oper.opt=="update" then
		-- 	local p = self.partnersData:getPartnerById(value.ID)
		-- 	if p then
		-- 		if not p:isHave() then
		-- 			p:setNew(true)
		-- 		end
		-- 		p:read(value)
		-- 	end
		-- elseif oper.opt=="delete" then
		-- 	local p = self.partnersData:getPartnerById(value.ID)
		-- 	if p then
		-- 		p:setIsHave(false)
		-- 	end
		-- end
		-- eventName="partner"
		-- eventArgs={uid,partnerID,partner,oper.opt}
	elseif oper.skillChoose then
		local value = oper.skillChoose
		local id = value.id
		local skillChoose = self.skillChooses[id]
		if oper.opt=="insert" or oper.opt=="update" then
			self.skillChooses[id] = value
			skillChoose = value
		elseif oper.opt=="delete" then
			skillChoose = nil
			self.skillChooses[id]=nil
		end
		eventName="skillChoose"
		eventArgs={id,skillChoose,oper.opt}
	elseif oper.activatedMount then
		local value = oper.activatedMount

		-- print("oper.activatedMount", oper.opt)
		-- dump(value,"oper.activatedMount")
        local mount = value.mount
		local id = mount.uid
		local activatedMount = self.activatedMounts[id]
		if oper.opt=="insert" then
            if not activatedMount then
            	activatedMount=Mount.new()
            end
			activatedMount:read(mount)
			activatedMount:setIndex(value.index+1)
            activatedMount:setHave(true)
            activatedMount:setIsNewGet(true)
            self.activatedMountNum = self.activatedMountNum + 1
			self.activatedMounts[id] = activatedMount
		elseif oper.opt=="update" then
			activatedMount:read(mount)
			activatedMount:setIndex(value.index+1)
			activatedMount:setHave(true)
            activatedMount:setIsNewGet(true)
		elseif oper.opt=="delete" then
			-- activatedMount = nil
			self.activatedMounts[id]=nil
			self.activatedMountNum = self.activatedMountNum - 1
		end

		if oper.opt=="insert" or oper.opt=="delete" then
			self.redPoint:checkStateByKey(Constant.FUNC_TYPE_MOUNT_PIT)
		end

		eventName="activatedMount"
		eventArgs={id,activatedMount,oper.opt}
		self:calUserdataAttr() -- 属性数据过期，重算
	elseif oper.mountHomeNum and oper.mountHomeNum > 0 then
		self.mountHomeNum = oper.mountHomeNum
		EM:notify(ViewEvent.Mount_OpenExtendSlot)
	elseif oper.lifeSkill then
		local value = oper.lifeSkill
		local id = value.uid
		if oper.opt=="insert" or oper.opt=="update" then
			self.lifeSkills[id] = value
		elseif oper.opt=="delete" then
			self.lifeSkills[id] = nil
		end
		eventName="lifeSkill"
		eventArgs={id,value,oper.opt}
	elseif oper.grid then
		local value = oper.grid
		if oper.opt=="update" then
			-- equipGrid 一定存在
			local equipGrid = self._equipGrids[value.location]
			local preFashionId = equipGrid:getAvatarFashionId()
			local hasAvatarChange, hasHiddenChange = equipGrid:updateValue(value)
			equipGrid:setEquip(self:getEquip(value.UUID))

			self:calUserdataAttr() -- 属性数据过期，重算

			eventName="equipGrid"
			eventArgs={equipGrid,preFashionId,hasAvatarChange, hasHiddenChange }

            local tempLv = 9999
            for _, v in pairs(Enums.GridCanStrengthen) do
                local grid = self._equipGrids[v]
                tempLv = math.min(tempLv, grid:getStrengthLevel())
            end
            self.minEquipStrengthLv = tempLv
        elseif oper.opt=="insert" then
		elseif oper.opt=="delete" then
		end

	elseif oper.userExpCard then -- 地城经验卡
		self._userExpCard = ActiveReward.new()
		self._userExpCard:read(oper.userExpCard)
		eventName="activeRewards"
		eventArgs={self._userExpCard}
	elseif oper.luckboxOpenTimes then
		local value = oper.luckboxOpenTimes
		if oper.opt == "insert" or oper.opt == "update" then
			self._luckBoxOpendTimesList[ value.typ ] = value
		elseif oper.opt=="delete" then
			self._luckBoxOpendTimesList[ value.typ ] = nil
		end
		-- dump(self._luckBoxOpendTimesList, "-------------------->>>>update luckBoxOpendTimesList")
		eventName = "luckBoxOpenedTimes"
		eventArgs = {value,oper.opt }
	elseif oper.fashion then
		--时装
		local value = oper.fashion --时装数据
		if oper.opt=="update" then
		elseif oper.opt=="insert" then
			--时装ID必然是唯一的
			local clothes = Clothes.new()
			clothes:read({tid = value.id})
			self._clothes[value.id] = clothes
			clothes:setIsNewGet(true)

			self:_refreshClothesNew(clothes)
			--TODO 新获得了时装 需要通知刷新下界面
		elseif oper.opt=="delete" then
		end
	elseif oper.grayBattleInfo then
		self.grayBattleInfo = oper.grayBattleInfo

		self:initGrayBattleNpcData()

		eventName = "grayBattleInfoUpdate"
		eventArgs = {self.grayBattleInfo}
	elseif oper.finishedSideTaskId > 0 then
		-- 支线任务完成
		if oper.opt=="insert" and (not table.hasvalue(self.finishedSideTaskIds, oper.finishedSideTaskId)) then
			table.insert(self.finishedSideTaskIds, oper.finishedSideTaskId)
			eventName = "sideTask"
			eventArgs = {oper.finishedSideTaskId }
		end
	elseif oper.DungeonRemainTimes then
		-- 副本次数更新
		local dungeonTimes = oper.DungeonRemainTimes
		self.dungeonTimesDict[dungeonTimes.ID] = dungeonTimes

		eventName = "dungeonTimes"
		eventArgs = {dungeonTimes.ID, dungeonTimes }
	elseif oper.closedFeature then
		for i,closedFeature in ipairs(oper.closedFeature) do
			local id = tonumber(closedFeature)
			if oper.opt == "insert" then
				self.closedFeatures[id] = id
			elseif oper.opt == "delete" then
				self.closedFeatures[id] = nil
			end

			if dispatchEvent then
				self:dispatchChange("closedFeature", id, oper.opt=="insert")
			end
		end
	end

	if dispatchEvent and eventName then
		self:dispatchChange(eventName,unpack(eventArgs))
	end

	-- self.dirty = true
end

function UserData:_refreshClothesNew(clothes)
	local idx = Constant.FASHION_LOCATION_2_CLOTHES_IDX[clothes:getLocation()]
	UD.redPoint:checkStateByKey(RedPointConstant["Clothes_" .. idx])
end

--服务端发送过来所有有时限的道具 主动推送
function UserData:onSpReward(rewards,isNotlogin)
	local oldSpRewardClothes = nil
	if isNotlogin then
		if self._spRewardClothes then
			oldSpRewardClothes = table.clone(self._spRewardClothes)
		end
	end

	self._spRewardClothes = {}
	self._spRewardMounts = {}
	self._spRewardPartners = {}
	self._spCollectors = {}
	self._spTitles = {}

	local titlestr = ""
	local saveSpTitleKey = "special_title_ids"
	local oldTitleStr = app:getValue(saveSpTitleKey, "0")

	self.partnersData:cleanSpReward()
	for k,v in ipairs(rewards) do
		local tp = protobuf.enum_id("pb_loot.Loot.LootType", v.loot.type) or v.loot.type
		local uuid = v.uuid
		local duration = v.duration

		if tp == 81 then
			--时装 目前时装数据中只有一个ID 而这里需要放的不仅仅是ID 还有UUID 和 时间
			local clothes = Clothes.new()
			clothes:read({tid = v.loot.id, duration = duration})

			self._spRewardClothes[v.loot.id] = clothes
			if isNotlogin and oldSpRewardClothes and not oldSpRewardClothes[v.loot.id] then
				clothes:setIsNewGet(true)
				self:_refreshClothesNew(clothes)
			end
		elseif tp == 4 then
			--坐骑
			local mount = Mount.new()
			mount:read({uid = uuid, tid = v.loot.id, duration = duration})
			mount:setHave(true)
			self._spRewardMounts [uuid] = mount
		elseif tp == 11 then
			--随从
		
			self.partnersData:updateBySpReward({id = tonumber(v.loot.id), duration = duration})
		elseif tp == 72 then
			self._spCollectors[v.loot.id] = v
		elseif tp == 83 then -- 称号
			self._spTitles[v.loot.id] = v
			if not oldTitleStr:find(tostring(v.loot.id)) then
				self:getNewSpTitles()[v.loot.id] = true
				UD.redPoint:checkStateByKey(Constant.FUNC_TYPE_PACK_TITLE)
			end
			titlestr = titlestr..tostring(v.loot.id)..","
		end
	end

	if titlestr ~= oldTitleStr and titlestr:len() > 0 then
		self._spTitleChange = true
	end
	app:saveValue(saveSpTitleKey, titlestr)
	if checknumber(self._activedID) ~= 0 and self._gotTitleIds and not self:isGotTitle(self._activedID) then
		self:reqActiveTitle(0, true)
	end

	--通知坐骑刷新
	UD:dispatchChange("mount", nil, nil, "reload")
	--刷新随从
	-- if PartnerEvent then
	-- 	PartnerEvent:dispatchEvent(PartnerEvent.TYPE.REFRESH_ALLITEM)
	-- end
end


function UserData:onChanged(name,listener)
	handle_index = handle_index + 1
	local handle = name and name .. "_" .. handle_index or tostring(handle_index)
	if name then
		local listeners = self._listenerDict[name] or {}
		listeners[handle]=listener
		self._listenerDict[name] = listeners
	else
		self._userListerner = listener
	end
	return handle
end

function UserData:unChanged(name,handle)
	if name then
		local listeners = self._listenerDict[name]
		if listeners and handle then
			listeners[handle]=nil
			self._listenerDict[name] = listeners
		end
	else
		self._userListerner = nil
	end
end

function UserData:dispatchChange(name,...)
	if self._userListerner then
		self._userListerner(name, ...)
	end

	local listeners = self._listenerDict[name] or {}
	for _,listener in pairs(listeners) do
		if listener then
			listener(...)
		end
	end
end

function UserData:getAutoJoinList()
	return self.autoJoinList
end

function UserData:clearAutoJoinList()
	self.autoJoinList = {}
end

function UserData:isSideTaskComp(taskId)
	return table.hasvalue(self.finishedSideTaskIds, taskId)
end

-- message DungeonRemainTimes{
-- 	int32 ID = 1;	//副本ID
-- 	int32 DailyTimes = 2;
-- 	int32 DailyLimit = 3;
-- 	int32 WeeklyTimes = 4;
-- 	int32 WeeklyLimit = 5;
-- }
function UserData:getDungeonTimes(dungeonId)
	return self.dungeonTimesDict[dungeonId]
end

function UserData:isFeatureClosedByServer(featureId)
	return self.closedFeatures[featureId] ~= nil
end

function UserData:removeLuckboxId()
	self.luckboxId = 0
end

function UserData:getLuckboxId()
    return self.luckboxId
end

function UserData:setLuckboxId(id)
	self.luckboxId = id
end

function UserData:getUid()
	return self.uid
end

function UserData:getLevel()
    return self.player.level
end

function UserData:getHeadShield()
	return self.isHeadShield
end

-- 充值开放
function UserData:isPayOpen()
	if app.channelAPI:canPay() and self.player.isPayOpen then
		return true
	end
    return false
end

--用来计算经验奖励的等级
function UserData:getExpRewardLevel()
	return self.player.rewardLevel
end

function UserData:updateExpRewardLv(lv)
	self.player.rewardLevel = lv
	--最好发一个通知
end

function UserData:getGold()
    return self._coinWallets[99] or 0
end

-- 钻石+赠送钻石
function UserData:getCoin()
	local coin = self._coinWallets[98] or 0
	if self._coinWallets[94] then
		coin = coin + self._coinWallets[94]
	end
    return coin
end

function UserData:getMagicDust()
    return self._coinWallets[92] or 0
end

function UserData:getRoseGold()
	return self._coinWallets[110] or 0
end

--新添加的货币 魔晶
function UserData:getMagicCrystal()
	return self._coinWallets[115] or 0
end

function UserData:getExpDaily()
    return self.player.expDaily
end


function UserData:getExpPool()
    return self.player.expPool
end


function UserData:getExp()
    return self.player.exp
end

-- 是否体力已经满了
function UserData:isPowerFull()
	local power = self:getPower()
	local conf = GD:queryHeroLevelUpByLevel(self.player.level)
	local powerMax = tonumber(conf.power)
	return power >= powerMax
end

-- 返回体力
function UserData:getPower()
    return self._coinWallets[96] or 0
end

-- 返回锦标赛星章点数
function UserData:getPvpStarCount()
	return self._coinWallets[84] or 0
end

-- 返回活动副本累积活动点数
function UserData:getActivityDungeonsPoint()
    return self._coinWallets[91] or 0
end

-- 返回地下城副本活动点数
function UserData:getDungeonsPoint()
	return self._coinWallets[121] or 0
end

-- 返回地下城副本掉落的整个宝箱个数
function UserData:getDungeonLuckBox()
	return self._coinWallets[122] or 0
end

-- 返回活动掉落的整个宝箱个数
function UserData:getEventLuckBox()
	return self._coinWallets[123] or 0
end

-- 返回竞标赛掉落的整个宝箱个数
function UserData:getArenaLuckBox()
	return self._coinWallets[124] or 0
end

-- 返回锦标赛总的星章数
function UserData:getArenaStarCount()
	local boxNum = UD:getArenaLuckBox()
	local maxPoint = UD:getLuckBoxLevelUpPoint(Enums.BoxType.pvp)
	return UD:getPvpStarCount() + boxNum * maxPoint
end

function UserData:getClass()
    return self.player.classID
end

function UserData:getGender()
    return self.player.gender
end

function UserData:isMe(uid)
    return self.player.uid == tonumber(uid)
end

--获取身上的格子信息
function UserData:getEquipGrids()
	return self._equipGrids
end

function UserData:getEquipGridByPos(pos)
	return self._equipGrids[pos]
end

-- 地城经验卡
function UserData:getUserExpCard()
	return self._userExpCard
end

-- 地城经验卡可开启最大次数(包括未激活的)
function UserData:getUserExpCardAllCount()
	return self._userExpCard:getAllCount()
end

-- 给定主线任务id和等级，当前是否满足条件
function UserData:isMainTaskAndLvMeet(taskId, lv, withReason)
	local isTaskMeet = true
	local reason
	if taskId then
		isTaskMeet = self:isMainTaskFinished(taskId)
		if withReason and not isTaskMeet then
			local taskConf = GD:queryTaskById(taskId)
			reason = string.format(L("ErrteamTargetTaskLock"), L(taskConf.name))
		end
	end

	local isLvMeet = true
	if lv then
		isLvMeet = tonumber(lv) <= self:getLevel()
		if withReason and not isLvMeet and not reason then
			reason = string.format(L("lua_code_text_5"), lv)
		end
	end

	return isTaskMeet and isLvMeet, reason
end

function UserData:setCurTask(task)
	if not task then return end
	if task:isMain() then
		self._curTask = task
	end
end

-- 监测id主任务是否接取
function UserData:isMainTaskToken(id)
	id = tonumber(id)
	local curTaskId = self:getCurTaskId()
	return id <= curTaskId
end

-- 判断主线任务Id是否完成
function UserData:isMainTaskFinished( id )
	id = tonumber(id)
	local curTaskId = self:getCurTaskId()
	if id == curTaskId then
		if self._curTask then
			return self._curTask:isFinished()
		else
			return true
		end
	else
		return id < curTaskId
	end
end

function UserData:getCurTask()
	return self._curTask
end

function UserData:getCurTaskId()
	local curTask = self:getCurTask()
	local curTaskId = curTask and tonumber(curTask:getId()) or 0
	return curTaskId
end

function UserData:isTaskFinished(taskId)
	local task = self:getTaskById(taskId)
	local finished = task and (not task:isTaken()) or false
	return finished
end

function UserData:isTaskTaken(taskId)
	local task = self:getTaskById(taskId)
	local taken = task and task:isTaken() or false
	return taken
end

function UserData:getCurTasks()
	local tasks = {}
	local mainTasks = {}

	for _,v in pairs(self.tasks) do
		if v:isTaken() then
			if v:isMain() then
				table.insert(mainTasks,v)
			else
				table.insert(tasks,v)
			end
		end
	end

	for i,v in ipairs(mainTasks) do
		table.insert(tasks, i, v)
	end

	return tasks
end

function UserData:getCurTakenMainTasks()
	local tasks = {}
	for _,v in pairs(self.tasks) do
		if v:isTaken() and v:isMain() then
			table.insert(tasks,v)
		end
	end
	return tasks
end

-- 反回主线任务，无论主线任务是什么状态
function UserData:getMainTask()
	if not self.tasks then return end
	for _,v in pairs(self.tasks) do
		if v:isMain() then
			return v
		end
	end
end
-- 获取当前 主线任务的task
function UserData:getMainTaskId()
	local task = self:getMainTask()
	if task then
		return task:getId()
	end
	return 999999999
end

function UserData:getAllBranchTasks(bSort)
	local tasks = {}
	local finishTasks = {}
	for _, v in pairs(self.tasks) do
		if v:isSide() and not v:isRewarded() then
			table.insert(tasks, v)
		end
	end
	if not bSort then return tasks end

	local finishTasks = {}
	local trackTasks = {}
	local noTrackTasks = {}
	local totalTasks = {}

	for _, task in ipairs(tasks) do
		if task:isFinished() then
			table.insert(finishTasks, task)
		else
			if TaskManager:isNeedTrack(task:getId()) then
				table.insert(trackTasks, task)
			else
				table.insert(noTrackTasks, task)
			end
		end
	end

	table.sort(finishTasks, function(a, b)
		return a.acceptStamp < b.acceptStamp
	end)

	table.sort(trackTasks, function(a, b)
		return a.acceptStamp < b.acceptStamp
	end)

	table.sort(noTrackTasks, function(a, b)
		return a.acceptStamp < b.acceptStamp
	end)

	for _, task in ipairs(finishTasks) do
		table.insert(totalTasks, task)
	end

	for _, task in ipairs(trackTasks) do
		table.insert(totalTasks, task)
	end

	for _, task in ipairs(noTrackTasks) do
		table.insert(totalTasks, task)
	end

	return totalTasks
end

function UserData:getTakenBranchTasks(bSort)
	local tasks = {}
	for _,v in pairs(self.tasks) do
		if v:isTaken() and v:isSide() then
			table.insert(tasks, v)
		end
	end

	if not bSort then return tasks end

	local trackTasks = {}
	local noTrackTasks = {}
	local totalTasks = {}

	for _, task in ipairs(tasks) do
		if TaskManager:isNeedTrack(task:getId()) then
			table.insert(trackTasks, task)
		else
			table.insert(noTrackTasks, task)
		end
	end

	table.sort(trackTasks, function(a, b)
		return a.acceptStamp < b.acceptStamp
	end)

	table.sort(noTrackTasks, function(a, b)
		return a.acceptStamp < b.acceptStamp
	end)

	for _, task in ipairs(trackTasks) do
		table.insert(totalTasks, task)
	end
	for _, task in ipairs(noTrackTasks) do
		table.insert(totalTasks, task)
	end

	return totalTasks
end

function UserData:getCurTakenDailyTasks()
	local tasks = {}
	for _,v in pairs(self.tasks) do
		if v:isDaily() and v:isTaken() then
			table.insert(tasks,v)
		end
	end
	return tasks
end

function UserData:getTotalDailyTasks()
	local tasks = {}
	for _,v in pairs(self.tasks) do
		if v:isDaily() then
			table.insert(tasks,v)
		end
	end
	return tasks
end

function UserData:getDailytTaskByPos(pos)
	for _,v in pairs(self.tasks) do
		if v:isDaily() and v:getPos() == pos then
			return v
		end
	end
end

function UserData:getFinishedDailyTasks()
	local tasks = {}
	for _,v in pairs(self.tasks) do
		if v:isDaily() and (v:isFinished() or v:isRewarded()) then
			table.insert(tasks,v)
		end
	end
	return tasks
end

function UserData:getTotalBountyTasks()
	local tasks = {}
	for _,v in pairs(self.tasks) do
		if v:isBounty() then
			table.insert(tasks,v)
		end
	end
	return tasks
end

function UserData:getCurTakenBountyTasks()
	local tasks = {}
	for _,v in pairs(self.tasks) do
		if v:isBounty() and v:isTaken() then
			table.insert(tasks,v)
		end
	end
	return tasks
end

function UserData:getAllWeeklyTasks()
	local tasks = {}
	for _, v in pairs(self.tasks) do
		if v:isWeekly() then
			table.insert(tasks, v)
		end
	end
	return tasks
end

function UserData:getFinishedWeeklyTasks()
	local tasks = {}
	for _, v in pairs(self.tasks) do
		if v:isWeekly() and (v:isFinished() or v:isRewarded()) then
			table.insert(tasks, v)
		end
	end
	return tasks
end

function UserData:getAllCompletedTasks()
	local tasks = {}
	for _,v in pairs(self.tasks) do
		if v:isFinished() or v:isRewarded() then
			table.insert(tasks,v)
		end
	end
	return tasks
end

function UserData:getAllCompletedTaskConfigs()
    local taskConfigs = {}
    local tasks = self:getAllCompletedTasks()
    for i,v in ipairs(tasks) do
        if v:getConfig() then
            table.insert(taskConfigs,v:getConfig())
        end
    end
    return taskConfigs
end

function UserData:getEliteMatchTasks()
	local tasks = {}
	for _, v in pairs(self.tasks) do
		if v:isEliteMatch() then
			table.insert(tasks, v)
		end
	end
	table.sort(tasks, function(a, b)
		return a.acceptStamp < b.acceptStamp
	end)
	return tasks
end

function UserData:getTaskById(id)
	local task = self.tasks[tonumber(id)]
	return task
end

function UserData:getTasks()
	return self.tasks
end

function UserData:getGrayBattleInfo()
	return self.grayBattleInfo
end

function UserData:hasGrayBattleInfo()
	return self.grayBattleInfo ~= nil and next(self.grayBattleInfo) ~= nil
end

function UserData:isGrayBattleFinished()
	if self:hasGrayBattleInfo() then
		if self.grayBattleInfo.endStamp <= (app.session:getServerTime() or app:getTime()) then
			return true
		end
	end
	return false
end

function UserData:getGrayBattleRewardGrade()
	if self:hasGrayBattleInfo() then
		return self.grayBattleInfo.rewardType
	end
end

function UserData:getGrayBattleSoulList()
	if self:hasGrayBattleInfo() then
		return self.grayBattleInfo.soul
	end
end

function UserData:getGrayBattleRemainTime()
	if self:hasGrayBattleInfo() then
		local endTime = self.grayBattleInfo.endStamp
		local now = math.floor(app.session:getServerTime())
		if now < endTime then
			return endTime - now
		else
			return 0
		end
	end
	return 0
end

function UserData:initGrayBattleNpcData()
	self.grayBattleNpcData = {}
	if self:hasGrayBattleInfo() then
		local mineInfos = self.grayBattleInfo.grayBattleMineInfos
		local mineIdAndNpcId
		local mineConfig
		local npcConfig
		local npcUid
		for _, mineInfo in ipairs(mineInfos) do
			-- mineId 也是npcId，潜规则
			mineIdAndNpcId = mineInfo.mineID
			mineConfig = GD:queryMineById(mineIdAndNpcId)
			npcConfig = GD:queryMapNpc(mineIdAndNpcId)
			for _, pos in ipairs(mineInfo.pos) do
				npcUid = NpcManager:generateNpcUid()
				self.grayBattleNpcData[npcUid] =
				{
					uid = npcUid,
					mId = tonumber(npcConfig.ID),
					mapId = tonumber(mineConfig.mapId),
					position = pos,
					npcConfig = npcConfig,
					battleId = mineInfo.battleID,
					mineId = mineIdAndNpcId
				}
			end
		end
	end
end

function UserData:getGrayBattleNpcs()
	return self.grayBattleNpcData
end

function UserData:getGrayBattleIdByPos(pos)
	if self.grayBattleInfo ~= nil then
		local mineInfos = self.grayBattleInfo.grayBattleMineInfos
		for _, mineInfo in ipairs(mineInfos) do
			if mineInfo.pos == pos then
				return mineInfo.battleID
			end
		end
	end
end

function UserData:getGatherDataByNpcId(npcId)
	return self.npcResourcePoints[npcId]
end

function UserData:getNpcDataByUid(npcUid)
	-- npcResourcePoints 存储的是npcId，不是uid
	-- if self.npcResourcePoints[npcUid] ~= nil then
	-- 	return self.npcResourcePoints[npcUid]
	-- end
	if self.grayBattleNpcData[npcUid] ~= nil then
		return self.grayBattleNpcData[npcUid]
	end
end

function UserData:getGrayBattleNpcDataByMapId(mapId)
	local mapNpcData = {}
	for uid, npcData in pairs(self.grayBattleNpcData) do
		if npcData.mapId == mapId then
			table.insert(mapNpcData, npcData)
		end
	end
	local function sortHelper(a, b)
		return a.position < b.position
	end
	table.sort(mapNpcData, sortHelper)
	return mapNpcData[1]
end

function UserData:getMountNum()
	local num = 0
	for k,v in pairs(self.mounts) do
		num = num + 1
	end

	if self._spRewardMounts then
		if self._spRewardMounts then
			for k,v in pairs(self._spRewardMounts) do
				num = num + 1
			end
		end
	end
	return num
end

-- 排除金腰带 坐骑
function UserData:getMountNumWithoutSpReward()
	local num = 0
	for k,v in pairs(self.mounts) do
		num = num + 1
	end
	return num
end


function UserData:getMountByID(tid)
    for k,v in pairs(self.mounts) do
        if v.tid==tid then
            return v
        end
	end

	if self._spRewardMounts then
		for k,v in pairs(self._spRewardMounts) do
			if v.tid==tid then
				return v
			end
		end
	end

	return nil
end

function UserData:isSpRewardMount(uid)
	if self._spRewardMounts then
		return self._spRewardMounts[uid]
	end
	return nil
end

function UserData:getAllActivityMounts()
	return self.mounts, self._spRewardMounts
end

function UserData:getMountByUid(uid)
	if self._spRewardMounts then
		if self._spRewardMounts and self._spRewardMounts[uid] then
			return self._spRewardMounts[uid]
		end
	end

	if self.mounts and self.mounts[uid] then
		return self.mounts[uid]
	end

	return nil
end

function UserData:getMounts()
	return self.mounts
end

-- 清理坐骑new
function UserData:clearMountsNew()
	for k,mount in pairs(self.mounts) do
		if mount.isNew then
			mount:setIsNewGet(false)
		end
	end
end

function UserData:getMount()
	local mountUID = self.player.mountUID
	local mount = self.mounts[mountUID]

	if not mount and self._spRewardMounts then
		mount = self._spRewardMounts[mountUID]
	end
	return mount
end

function UserData:getMountTID()
	local mount = self:getMount()
    if mount then
        return mount.tid
	end
	return nil
end

-- 获取坐骑灵魂石数量
function UserData:getMountSoulCountById(id)
	local mountSoul = self.mountSouls[id]
	return mountSoul and mountSoul:getAmount() or 0
end

-- 获取随从灵魂石数量
function UserData:getPartnerSoulCountById(id)
	local partnerSoul = self.partnerSouls[id]
	return partnerSoul and partnerSoul:getAmount() or 0
end

function UserData:getNearestResourcePointByType(nType,mapId,ox)
	mapId = mapId or 0
	local npcId = nil
	local tempX = 0
	for k,v in pairs(self.npcResourcePoints) do
		local oreC = GD:queryOreConfigById(v.id)
		if oreC then
			local rType = tonumber(oreC.refreshType)
			if rType == 1 and tonumber(oreC.type) == nType and ((tonumber(oreC.mapId) == mapId) or (mapId == 0)) then
				local px = tonumber(oreC.coordinate)
				if px then
					local disx = math.abs(px - ox)
					if tempX > disx then
						tempX = disx
						npcId = v.id
					elseif tempX == 0 then
						tempX = disx
						npcId = v.id
					end
				end
			end
		end
	end
	return npcId
end

-- function UserData:isNpcExist(npcId)
--     for k,v in pairs(self.npcResourcePoints) do
--         local npc = v
--         if tonumber(npc.id) == tonumber(npcId) then
--             return true
--         end
--     end
--     return false
-- end

--是否在好友中
function UserData:isFriend(uid)
    if self.friends then
	    return self.friends[uid] ~= nil
    end
    return false
end

--是否在黑名单中
function UserData:isBlack(uid)
    if self.blacks then
    	return self.blacks[uid] ~= nil
    end
    return false
end

--是否在公会中
function UserData:isInGuild()
	return app:sendMsg("NewguildModel", "hasGuild")
end
function UserData:getGuildId()
	return app:sendMsg("NewguildModel", "getGuildId")
end
function UserData:getGuildName()
	return app:sendMsg("NewguildModel", "getGuildName")
end

function UserData:isGuildLeader(uid)
	return app:sendMsg("NewguildModel", "isGuildLeader", uid)
end

function UserData:getLifeSkills()
    return self.lifeSkills
end

function UserData:getLifeSkillById(id)
	return self.lifeSkills[tonumber(id)]
end

function UserData:isActivatedMountEquiped(uid)
    local mount = self.activatedMounts[tostring(uid)]
    return mount ~= nil
end

function UserData:getActivatedMountByIndex(index)
    for k,v in pairs(self.activatedMounts) do
        if v.index == index then
            return v
        end
    end
end

function UserData:getActivatedMounts()
    return self.activatedMounts
end

function UserData:getActivatedMountNum()
	return self.activatedMountNum
end

-- 坐骑激活是否已满
function UserData:isActivatedMountFull()
	if UD.mountHomeNum > 0 then
		return self.activatedMountNum >= UD.mountHomeNum
	else
		return self.activatedMountNum >= Constant.MOUNT_ACTIVE_NUM_MAX
	end
end

function UserData:setCombatPower(combatPower)
    self.player.combatPower=combatPower
end

function UserData:getCombatPower()
    return self.player.combatPower
end

-- 返回背包等级
function UserData:getBagLv()
	return self.bag:getBagLv()
end

-- 当前背包等级是否最大等级
function UserData:isCurBagLvMax()
	return self.bag:isCurBagLvMax()
end

-- 返回bag中的宝石
function UserData:getJewels()
	local jewelsTemp = {}
	for k,v in pairs( self.bag.items ) do
        if v.itemBagType == Enums.ItemBagType.jewel then
            jewelsTemp[#jewelsTemp + 1] = v
        end
	end
	return jewelsTemp
end

function UserData:getAllJewels()
    self.allJewels = {}
    for _,v in pairs(self:getJewels()) do
        local j=clone(v)
        j:setOrderLevel(3)
        j:setState(Enums.JewelState.inBag)
        self.allJewels[j.uid] = j
    end
    for k,v in pairs(UD.equips) do
        if v.jewelSlots then
            for k1,v1 in pairs(v.jewelSlots) do
                if v1.jewel then
                    local j=clone(v1.jewel)
                    j:setEquipTid(v.tid)
                    j:setEquipUid(v.uid)
                    j:setOrderLevel(1)
                    j:setState(Enums.JewelState.inSlot)
                    self.allJewels[j.uid] = j
                end
            end
        end
        if v.lockedJewelSlot and v.lockedJewelSlot.jewel then
            if v.lockedJewelSlot.jewel then
                local j=clone(v.lockedJewelSlot.jewel)
                j:setEquipTid(v.tid)
                j:setEquipUid(v.uid)
                j:setOrderLevel(1)
                j:setState(Enums.JewelState.inSlot)
                self.allJewels[j.uid] = j
            end
        end
    end
    for k,v in pairs(UD:getItems()) do
        if tonumber(v.itemBagType)==Enums.ItemBagType.equip then
            if v.jewelSlots then
                for k1,v1 in pairs(v.jewelSlots) do
                    if v1.jewel then
                        local j=clone(v1.jewel)
                        j:setEquipTid(v.tid)
                        j:setEquipUid(v.uid)
                        j:setOrderLevel(2)
                        j:setState(Enums.JewelState.inSlot)
                        self.allJewels[j.uid] = j
                    end
                end
            end
            if v.lockedJewelSlot and v.lockedJewelSlot.jewel then
                if v.lockedJewelSlot.jewel then
                    local j=clone(v.lockedJewelSlot.jewel)
                    j:setEquipTid(v.tid)
                    j:setEquipUid(v.uid)
                    j:setOrderLevel(2)
                    j:setState(Enums.JewelState.inSlot)
                    self.allJewels[j.uid] = j
                end
            end
        end
    end
	return self.allJewels
end

function UserData:getJewel(uid)
	if not self.allJewels then
		self.allJewels = self:getAllJewels()
	end 
	return self.allJewels[uid]
end

--获取角色现在装备的所有装备上的宝石的总评分
function UserData:getCurEquipedJewelScore()
	local score = 0
	for k,v in pairs(UD.equips) do
		if v.jewelSlots then
			for k1,v1 in pairs(v.jewelSlots) do
				if v1:hasJewel() then
					score = score + v1.jewel:getGearScore()
				end
			end
		end
	end

	return score
end


function UserData:getItems()
	return self.bag.items
end

function UserData:getItem(uid)
	local item = self.bag.items[tostring(uid)]
	return item
end

--背包里的道具
function UserData:getItemByTid(itemId)
	for k,item in pairs(self:getItems()) do
		if item.tid == tonumber(itemId) then
			return item
		end
	end
end

function UserData:getItemAmountByTid(itemtid)
	local amount = 0
	for k,v in pairs(self:getItems()) do
		if tonumber(v.tid) == tonumber(itemtid) then
			amount = amount + v.amount
		end
	end
	-- print("itemtid, amount", itemtid, amount)
	return amount
end

function UserData:isItemExsit(itemId)
	for k,v in pairs(self:getItems()) do
		if tonumber(v.tid) == tonumber(itemId) then
			return true
		end
	end
	return false
end

function UserData:isItemExsitByNum(itemId,num)
	local amount = self:getItemAmountByTid(itemId)
	return amount >= num
end

-- 获取某个位置的装备
function UserData:getEquipByPos(pos)
	for _,equip in pairs(self.equips) do
		if equip:getPos() == pos then
			return equip
		end
	end
	return nil
end

function UserData:getEquip(uid)
	local equip = self.equips[tostring(uid)]
	return equip
end

-- 一件装备是否装在身上
function UserData:isEquiped( equipDataTemp )
	local isWear = false -- 默认是没装在身上的
	if equipDataTemp and equipDataTemp.uid then
		isWear = nil ~= self.equips[tostring(equipDataTemp.uid)]
	end
	return isWear
end

function UserData:getEquipIds()
	local equipIds = {}
	for k,v in pairs(self.equips) do
		table.insert(equipIds,v.tid)
	end
	return equipIds
end

-- 身上可转移附加属性的所有装备
function UserData:getCanTransAttrEquips()
	local equips = {}
	for k, v in pairs(self.equips) do
		if v:getExtraAttrNum() > 0 then
			table.insert(equips, v)
		end
	end
	table.sort(equips, function(a, b)
		return a.location < b.location
	end)
	return equips
end

function UserData:getToolAmountByTid(toolId)
	for k,v in pairs(self.tools) do
		local tool = v
		if tonumber(tool.tid) == tonumber(toolId) then
			return tool.amount or 1
		end
	end
    return 0
end

function UserData:isToolExistWithTid(toolId)
	return self.tools[tonumber(toolId)]
end

function UserData:getToolAmountByMainType(mainType)
	local amount = 0
	if self.tools then
		for k,v in pairs(self.tools) do
			local toolConfig = GD:getToolConfig(v.tid)
			if toolConfig and tonumber(toolConfig.mainType) == tonumber(mainType) then
				amount = amount + 1
			end
		end
	end
	return amount
end

function UserData:isHaveToolByMainType(mainType)
	return self:getToolAmountByMainType(mainType)>0
end

function UserData:getPlayer()
	return self.player
end

function UserData:getNickName()
	return self.player.name
end

function UserData:getDaibiValue(id)
	id = tonumber(id)
	local value = 0
	if id == Enums.lootType.coin then
		-- 赠送钻石算在钻石数量里面
		value = self:getCoin()
	elseif id == Enums.lootType.roseGold then
		-- 玫瑰金币（玫瑰金币实际是道具，但有货币配置）
		value = self:getItemAmountByTid(Constant.RoseCoin_ItemId)
	else
		value = self._coinWallets[id] or 0
	end
	return value
end

function UserData:getFameWithId(id)
	local fame = self.fames[tostring(id)]--id即为uid
	return fame
end

function UserData:getFameTotalCountWithId(id, subKey)
	local fameInfo = self:getFameWithId(id)
	local iCount = fameInfo.exp
    local isWorldFameFlag = GD:isWorldFame(subKey)
	local fameLevelUp = GD:queryFameLevelUp(isWorldFameFlag)

	for i, data in ipairs(fameLevelUp) do
		if i >= fameInfo.level then break end
		iCount = iCount + tonumber(data.exp)
	end

	return iCount
end

function UserData:getFameCountBySubKey(subKey)
	local iAlreadyCount = 0
	local fames = GD:queryFameBySubKey(subKey)

	for _, data in ipairs(fames) do
		local fameId = tonumber(data.ID)
        local subKey = tonumber(data.subKey)
		local iEachCount = self:getFameTotalCountWithId(fameId, subKey)
		iAlreadyCount = iAlreadyCount + iEachCount
	end

	return iAlreadyCount
end

function UserData:getMapBuffs()
	return self.mapBuffs
end

--获得由先后顺序的mapBuff的UID列表
function UserData:getSortMapBuffIds()
	return self._mapBuffUIds
end

-- 跨服副本匹配逃跑惩罚中
function UserData:isDungeonCrossMatchPunish()
	for i,mapBuff in pairs(self.mapBuffs) do
		if mapBuff.tid == Constant.MAP_BUFF_CANCEL_PUNISH or
			mapBuff.tid == Constant.MAP_BUFF_ESCAPE_PUNISH then
			return true
		end
	end
	return false
end

function UserData:getMapBuffByUid(uid)
	return self.mapBuffs[uid]	
end

function UserData:getAchievement(uid)
	local achievement = self.achievements[tostring(uid)]
	return achievement
end

function UserData:isAchievementComplete(uid)
	local achievementTemp = self:getAchievement( uid )
	return achievementTemp and achievementTemp:isComp() or false
end

function UserData:isAchievementReceived(uid)
	local achievementTemp = self:getAchievement( uid )
	return achievementTemp and achievementTemp:isReceived() or false
end

function UserData:hasCanGetRewardDailyTask()
	for k,v in pairs(self.achievements) do
		if v.timeType and v.timeType==2 and tonumber(v.state)==1 and tonumber(v.showType) ~= 1 then
			return true
		end
	end
	return false
end

function UserData:getShowAchievementsByType(typeId)
    local achIds =GD:getAchievementConfigByType(typeId)
    local showAchIds = {}
    local count = 1
    if achIds then
        for k,achConfig in pairs(achIds) do
        	if tonumber(achConfig.showType) ~= 1 then
	            local achId = tonumber(achConfig.ID)
	            if achConfig.pre == nil then--没有前置成就 加入显示序列
	                table.insert(showAchIds,count,achId)
	                count = count + 1
	            else--从服务器数据中检索前置成就是否完成以及领奖,前置成就完成或已领奖加入显示序列
	                local achievement = self:getAchievement(achConfig.pre)
	                if achievement then
	                    local state = tonumber(achievement.state)
	                    if state == 1 or state == 2 then
	                        table.insert(showAchIds,count,achId)
	                        count = count + 1
	                    end
	                end
	            end
        	end
        end
    end
    return showAchIds
end

-- 刷新公会红点提示
function UserData:updateGuildNewPoint( isNew )
	if isNew then
		self.badge:setNum(Constant.FUNC_TYPE_GANG,1)
	else
		self.badge:setNum(Constant.FUNC_TYPE_GANG,0)
	end
	-- self.dirty = true
end

-- 刷新福利红点提示
function UserData:updateWelfareNewPoint( id ,isNew )
	if id then
		if isNew then
			self.badge:setNum(id,1)
		else
			self.badge:setNum(id,0)
		end
		-- self.dirty = true
	end
end

 --判断某类成就是否有可以取得的奖励
function UserData:hasCanGetRewardAchievementByType(typeId)
    --dump(typeId,"Utils.hasCanGetRewardAchievementByType()")
	local showAchIds = self:getShowAchievementsByType(typeId)
    for k,v in pairs(showAchIds) do
        --print("showAchIds"..v)
        local achievement = self:getAchievement(v)
        if achievement and achievement.state == 1 then
            return true
        end
    end
    return false
end

function UserData:getAllRecommendAchievements()
    local function isAchCompleted(achId)
        local achievement = self:getAchievement(achId)
        if not achievement then return false end
        local isCompleted = false
        local state = tonumber(achievement.state)
        if state == 0 then--未完成
            isCompleted = false
        elseif state == 1 then--已完成
            isCompleted = true
        elseif state == 2 then--已领取
            isCompleted = false
        end
        return isCompleted
    end

    -- local function isAchUnCompleted(achId)
    --     local achievement = UD:getAchievement(achId)
    --     if not achievement then return false end
    --     local isUnCompleted = false
    --     local state = tonumber(achievement.state)
    --     if state == 0 then--未完成
    --         isUnCompleted = true
    --     elseif state == 1 then--已完成
    --         isUnCompleted = false
    --     elseif state == 2 then--已领取
    --         isUnCompleted = false
    --     end
    --     return isUnCompleted
    -- end

    local function isAchGetReward(achId)
        local achievement = self:getAchievement(achId)
        if not achievement then return false end
        local isGetReward = false
        local state = tonumber(achievement.state)
        if state == 0 then--未完成
            isGetReward = false
        elseif state == 1 then--已完成
            isGetReward = false
        elseif state == 2 then--已领取
            isGetReward = true
        end
        return isGetReward
    end

    local showAch = {}
    local unCompletedAchs = {}
    local unRecommentAchs = {}
    local achievements = GD:quereAllAchievements()
    for k,v in pairs(achievements) do
    	local temp = v:clone()
        local achId = tonumber(temp.ID)
        -- if v.recommend then

        -- end --self:getAchievement(achId) and
        if not isAchGetReward(achId) then
            if v.pre == nil then--没有前置成就 加入显示序列
                if isAchCompleted(achId) then
                    -- temp.recommend = 0 + (tonumber(v.recommend) or 1000)
                    temp.recommend = 0 + (tonumber(v.recommend) or 0)
                    table.insert(showAch,temp)
                else
                    -- temp.recommend = 2000 + (tonumber(v.recommend) or 1000)
                    if v.recommend then
                    	temp.recommend = 0 + (tonumber(v.recommend) or 1000)
                    	table.insert(unCompletedAchs,temp)
                    else
                    	table.insert(unRecommentAchs,temp)
                   	end
                end
            else--从服务器数据中检索前置成就是否领奖,前置成就已领奖加入显示序列
                if isAchGetReward(v.pre) then
                    if isAchCompleted(achId) then
                        -- temp.recommend = 0 + (tonumber(v.recommend) or 1000)
                        temp.recommend = 0 + (tonumber(v.recommend) or 0)
                        table.insert(showAch,temp)
                    else
                        -- temp.recommend = 2000 + (tonumber(v.recommend) or 1000)
                        if v.recommend then
                        	temp.recommend = 0 + (tonumber(v.recommend) or 1000)
                        	table.insert(unCompletedAchs,temp)
                    	else
                       		table.insert(unRecommentAchs,temp)
                       	end
                    end

                end
            end
        end
    end

    table.sort(showAch, function(a,b) return tonumber(a.recommend) < tonumber(b.recommend) end)
    table.sort(unCompletedAchs, function(a,b) return tonumber(a.recommend) < tonumber(b.recommend) end)
    table.sort(unRecommentAchs, function(a,b) return tonumber(a.ID) < tonumber(b.ID) end)
    for i,v in ipairs(unCompletedAchs) do
    	table.insert(showAch,v)
    end
    for i,v in ipairs(unRecommentAchs) do
    	table.insert(showAch,v)
    end

    -- for i,v in ipairs(showAch) do
    -- 	print("--------------- i = ",i)
    -- 	print("--------------- v.ID = ",v.ID)
    -- 	print("--------------- v.recommend = ",v.recommend)
    -- end
    local showAchIds = {}
    -- for i,v in ipairs(showAch) do
    --     if i <= 6 then
    --         table.insert(showAchIds,tonumber(v.ID))
    --     end
    -- end
    local takenAchIds = {}
    takenAchIds[1] = {}
    takenAchIds[2] = {}
    takenAchIds[3] = {}

    for i,v in ipairs(showAch) do
    	local timeType = tonumber(v.time)
    	if timeType == 1 then--获得永久--四条
    		if #takenAchIds[1] < 4 then
    			table.insert(takenAchIds[1],tonumber(v.ID))
    		end
    	elseif timeType == 3 then--获得每周--1条
    		if #takenAchIds[2] < 1 then
    			local achId = tonumber(v.ID)
    			if self:getAchievement(achId) then
    				table.insert(takenAchIds[2],achId)
    			end
    			-- table.insert(takenAchIds[2],achId)
    		end
    	elseif timeType == 2 then--获得每日--1条
    		if #takenAchIds[3] < 1 then
    			local achId = tonumber(v.ID)
    			if self:getAchievement(achId) then
    				table.insert(takenAchIds[3],achId)
    			end
    			-- table.insert(takenAchIds[3],achId)
    		end
    	end
    end
    for i,v in ipairs(takenAchIds) do
    	for i1,v1 in ipairs(v) do
    		table.insert(showAchIds,v1)
    	end
    end
    return showAchIds
end

function UserData:getFormulaIds()
	return self.formulaIds
end

--玩家是否拥有新的配方
function UserData:hasNewGetFormulaId()
	for k,v in pairs(self.formulaIds) do
		if v:isNewGet() then
			return true
		end
	end
	return false
end

--清理所有新配方
function UserData:clearFormulaIdsNew()
	for k,v in pairs(self.formulaIds) do
		if v:isNewGet() then
			v:setIsNewGet(false)
		end
	end
	UD.redPoint:clearStateByKey(Constant.FUNC_TYPE_COMPOUND)
end


--判斷配方是否是新獲得
function UserData:isFormulaNewGet(id)
	local info = self.formulaIds[tonumber(id)]
	if info then
		return info:isNewGet()
	end
	return false
end

--設置配方是否是新獲得
function UserData:setFormulaNewGet(id, bl)
	local info = self.formulaIds[tonumber(id)]
	if info then
		return info:setIsNewGet(bl)
	end
end

-- 道具学习配方，是否可以学习 （生活技能开放 and 未学习）
function UserData:isFormulaCanStudy(id)
	local isHave = self.formulaIds[id] ~= nil
	if not isHave then
		local conf = GD:getFormulaConfig(id)
		local lifeSkillId = tonumber(conf.subkey)
		local lifeSkill = self:getLifeSkillById(lifeSkillId)
		return lifeSkill ~= nil
	end
	return false
end

function UserData:isHasFormula(id,skillId)
	local have = false
	local fId = self.formulaIds[tonumber(id)]
	if not fId then
		local skill = self:getLifeSkillById(skillId)
		local formulaC = GD:getFormulaConfig(id)
		if skill and formulaC and formulaC.ID then
			local value1 = tonumber(formulaC.value1) or 1
			if skill.level >= value1 then
				have = true
			end
		end
	else
		have = true
	end
	return have
end

function UserData:updateSetting(setting)
	self.setting = setting
	self.dirty = true
end

function UserData:updateLocalStorage(localStorage)
	self.localStorage = localStorage
	self.dirty = true
end

function UserData:hasSpCollector(id)
	if self._spCollectors == nil then
		return false
	end

	return self._spCollectors[id] ~= nil
end

function UserData:getSpTitles()
	return self._spTitles
end

function UserData:getNewSpTitles()
	if not self._newSpTitles then
		self._newSpTitles = {}
	end
	return self._newSpTitles
end

function UserData:isSpTitleChange()
	return checkbool(self._spTitleChange)
end

function UserData:resetSpTitleChange()
	self._spTitleChange = false
end



-- function UserData:UD.partnersData:getPartnerById(id)
-- 	id = tostring(id)

-- 	local partner
-- 	if self._spRewardPartners then
-- 		partner = self._spRewardPartners[id]
-- 	end

-- 	if not partner then
-- 		partner = self.partners[id]
-- 	end

-- 	return partner
-- end

-- function UserData:isPartnerExsitByTid(id)
-- 	return self.partnersData:getPartnerById(id) ~= n
-- end

-- function UserData:getAllActivityPartners()
-- 	return self.partners, self._spRewardPartners
-- end

-- function UserData:isPartnerMaxQuality(id)
-- 	local partner = self.partnersData:getPartnerById(id)
-- 	if partner then
-- 		return partner.quality == Enums.partnerMaxQuality
-- 	end
-- 	return false
-- end

-- function UserData:getEquippedPartner()
-- 	return self:UD.partnersData:getPartnerById(self.player.partnerID)
-- end

-- function UserData:isSpRewardPartner(id)
-- 	id = tostring(id)

-- 	if self._spRewardPartners then
-- 		return self._spRewardPartners[id] ~= nil
-- 	end

-- 	return false
-- end

-- function UserData:getPartnerNpcId(partner)
-- 	local npcId
-- 	if partner then
-- 		npcId = GD:getPartnerNpcIdByPartnerId(partner.id,partner.quality)
-- 	end
-- 	return npcId
-- end
	
function UserData:isPartnerEquipByTid(tid)
	return tostring(self.player.partnerID) == tostring(tid)
end

-- key 是引导的id转化成的string，这里要求key都可以被转成int，服务器log有做转int操作
function UserData:saveKeyValueForTutorial(key,value)
	if self.kvStores then
		if not self.kvStores.tutorial then
			self.kvStores.tutorial = {}
		end
		local tKey = tostring(key)
		local keyValue = self.kvStores.tutorial[tKey]
		if not keyValue then
			keyValue = KeyValue.new()
			self.kvStores.tutorial[tKey] = keyValue
		end
		keyValue:read({key = tKey,value = value})
		-- self.dirty = true
	end
end

function UserData:getValueFromTutorialByKey(key)
	if self.kvStores and self.kvStores.tutorial then
		local keyValue = self.kvStores.tutorial[tostring(key)]
		if keyValue then
			return keyValue.value
		end
	end
	return nil
end

-- 引导是否结束，self.kvStores.generic.guideOver == "1"
function UserData:isGuideOver()
	local key = "guideOver"
	local value = self:getValueFromGenericByKey(key)
	if value and value == "1" then
		return true
	end
	return false
end

function UserData:saveGeneric(key, value,callFunc)
	local key = tostring(key)
    local value = tostring(value)
    local function callback(msg)
        if msg.ok then
             UD:saveKeyValueForGeneric(key,value)
             if callFunc then
             	callFunc()
             end
        end
    end
    app.session:request("kvstore.C2S_PutKVItem",{category = "generic",item = {key = key,value = value}},callback)
end

function UserData:saveKeyValueForGeneric(key,value)
	if self.kvStores then
		if not self.kvStores.generic then
			self.kvStores.generic = {}
		end
		local tKey = tostring(key)
		local keyValue = self.kvStores.generic[tKey]
		if not keyValue then
			keyValue = KeyValue.new()
			self.kvStores.generic[tKey] = keyValue
		end
		keyValue:read({key = tKey,value = value})
		-- self.dirty = true
	end
end

function UserData:getValueFromGenericByKey(key)
	if self.kvStores and self.kvStores.generic then
		local keyValue = self.kvStores.generic[tostring(key)]
		if keyValue then
			return keyValue.value
		end
	end
	return nil
end

function UserData:isInfiniteBuffIdExsit(buffId)
	if self.infiniteBuffIds then
	    for i,v in ipairs(self.infiniteBuffIds) do
	        local bId = v
	        if buffId == bId then
	            return true
	        end
	    end
	end
    return false
end
function UserData:addInfiniteBuffId(buffId)
	self.infiniteBuffIds = self.infiniteBuffIds or {}
    if not self:isInfiniteBuffIdExsit(buffId) and self.infiniteBuffIds then
        local buffConfig = GD:getBuffConfig(buffId)
        if buffConfig and buffConfig.ID then
            table.insert(self.infiniteBuffIds,buffId)
            table.sort(self.infiniteBuffIds, function(a,b)
                local aConfig = GD:getBuffConfig(a)
                local bConfig = GD:getBuffConfig(b)

                local aSort = aConfig.sort or 10000
                local bSort = bConfig.sort or 10000

                return aSort < bSort
            end)
            return true
        end
    end
    return false
end
function UserData:getInfiniteBuffIds()
    return self.infiniteBuffIds or {}
end
function UserData:removeInfiniteBuffId(buffId)
	if self.infiniteBuffIds then
	    for i = #self.infiniteBuffIds, 1, -1 do
	        local bId = self.infiniteBuffIds[i]
	        if buffId == bId then
	            table.remove(self.infiniteBuffIds,i)
	            return true
	        end
	    end
	end
    return false
end
function UserData:clearInfiniteBuffIds()
	if self.infiniteBuffIds then
	    local len = #self.infiniteBuffIds
	    if len > 0 then
	        self.infiniteBuffIds = {}
	        return true
	    end
	end
    return false
end

----------------------------------------->>>>>>>>>>>>>>>>> 时装相关
-- 某一件时装是否新获得
function UserData:isNewGetClothes( clothesID )
	local clothes = self:getClothesById(clothesID)
	if clothes then
		return clothes.isNew
	end
	return false
end

-- 时装是否激活？
function UserData:isClothesActive( clothesID )
	return self:getClothesById(clothesID) ~= nil
end

--判断时装是否是因为爵位或者时间限制发送过来的
function UserData:isSpRewardClothes( clothesID)
	if self._spRewardClothes then
		return self._spRewardClothes[clothesID] ~= nil
	end
	return false
end

--判断时装是否是因为爵位或者时间限制发送过来的
function UserData:getSpRewardClothesById( clothesID)
	if self._spRewardClothes then
		return self._spRewardClothes[clothesID]
	end
	return nil
end

function UserData:getClothesById(clothesID)
	local ret
	if self._spRewardClothes then
		ret = self._spRewardClothes[clothesID]
	end

	if not ret then
		return self._clothes[clothesID]
	end
	
	return ret
end

function UserData:getAllActivityClothes()
	return self._clothes, self._spRewardClothes
end

function UserData:clearClothesNewByIdx(idx)
	local hasNew = false
	if idx then
		local location = Constant.CLOTHES_IDX_2_FASHION_LOCATION[idx]
		for k,v in pairs(self._clothes) do
			if v:getLocation() == location then
				if v.isNew then
					v:setIsNewGet(false)
					hasNew = true
				end
			end
		end
		if self._spRewardClothes then
			for k,v in pairs(self._spRewardClothes) do
				if v:getLocation() == location then
					if v.isNew then
						v:setIsNewGet(false)
						hasNew = true
					end
				end
			end
		end
		if hasNew then
			self.redPoint:setStateByKey(RedPointConstant["Clothes_" .. idx], false)
		end
	else
		for k,v in pairs(self._clothes) do
			if v.isNew then
				v:setIsNewGet(false)
				hasNew = true
			end
		end
		if self._spRewardClothes then
			for k,v in pairs(self._spRewardClothes) do
				if v.isNew then
					v:setIsNewGet(false)
					hasNew = true
				end
			end
		end
		if hasNew then
			self.redPoint:clearStateByKey(Constant.FUNC_TYPE_PACK_WARDROBE)
		end
	end
end

function UserData:getClothesNewByIdx(idx)
	if idx then
		local location = Constant.CLOTHES_IDX_2_FASHION_LOCATION[idx]
		for k,v in pairs(self._clothes) do
			if v:getLocation() == location then
				if v.isNew then
					return true
				end
			end
		end
		if self._spRewardClothes then
			for k,v in pairs(self._spRewardClothes) do
				if v:getLocation() == location then
					if v.isNew then
						return true
					end
				end
			end
		end
	else
		for k,v in pairs(self._clothes) do
			if v.isNew then
				return true
			end
		end
		if self._spRewardClothes then
			for k,v in pairs(self._spRewardClothes) do
				if v.isNew then
					return true
				end
			end
		end
	end
	return false
end

-------------------------------------end时装-------------------

-- 通过装备部位获取强化信息
function UserData:getEquipGridStrengthByPos( pos )
	local equipGrid = self._equipGrids[pos]
	assert( equipGrid, " --------------->>>>>>>>>>>> 通过装备部位获取强化信息时，保存的值为空" )
	return equipGrid:getStrengthLevel()
end
-----------------------------------------<<<<<<<<<<<<<<<<<

-- 从新发生改变的声望中移除
function UserData:removeFromNewGotRenown( fameID )
	local index = table.indexof( self._newGotRenownList, fameID )
	assert( index, " ---------->>>>>> 要移除的新声望不存在于列表中了 " )
	table.remove( self._newGotRenownList, index )
	UD.redPoint:checkStateByKey(Constant.FUNC_TYPE_PACK_PRESTIGE)
end
-- 是否有新发生改变声望
function UserData:isNewGotRenownExist()
	for k,v in ipairs( self._newGotRenownList ) do
		if 0 < tonumber( v ) then
			return true
		end
	end
	return false
end
-- 某个声望是否新获得
function UserData:isNewGotRenown( fameID )
	if table.indexof( self._newGotRenownList, fameID ) then
		return true
	end
	return false
end
-- 清空新获得声望列表
function UserData:clearNewGotRenown()
	self._newGotRenownList = {}
end

-- 宝物panel的New标记显示状态
function UserData:isNewRareExist()
	return self:isCharmNumNew() or (self._userExpCard:getAllCanReceivedCount() > 0)
end
-- 幸运星数量是否增多
function UserData:isCharmNumNew()
	return self._newCharmNum
end

function UserData:setCharmNumNew(trueOrFalse)
	self._newCharmNum = trueOrFalse
	UD.redPoint:setStateByKey(RedPointConstant.Bag_NewCharm, self._newCharmNum)
end

-- 清除幸运星数量new标记
function UserData:clearCharmNumNew()
	self:setCharmNumNew(false)
end

function UserData:getAvatarParams(inBattle, autoAudio)
	local info = self.player:getUserBaseInfo()
	info.mountID = self:getMountTID()
	info.guildID = self:getGuildId()
	info.guildName = self:getGuildName()

	local fashionIDs = {}
	for k,v in pairs(self._equipGrids) do
        if (v:getLocation() ~= Enums.EquipType.head) or ((v:getLocation() == Enums.EquipType.head) and v:getHidden() == false) then
		    if v:getAvatarFashionId() > 0 then 
			    table.insert(fashionIDs, v:getAvatarFashionId())
		    end
        end
	end
	info.fashionIDs = fashionIDs

	info.titleID = self:getActivedTitleId()

	info.inBattle = inBattle or false
	info.autoAudio = autoAudio or false
	return info
end

function UserData:getFashionIDs(ignoreToy, ignoreHead)
	ignoreToy = ignoreToy or false
	ignoreHead = ignoreHead or false

	local fashionIDs = {}
	local fashionId, location
	for k,v in pairs(self._equipGrids) do
		fashionId = v:getAvatarFashionId()
		if fashionId > 0 then
			location = v:getLocation()
			if location == Enums.EquipType.toy then
				if not ignoreToy then
					table.insert(fashionIDs, fashionId)
				end
			elseif location == Enums.EquipType.head then
				if not ignoreHead then
					table.insert(fashionIDs, fashionId)
				end
			else
				table.insert(fashionIDs, fashionId)
			end
		end
	end
	return fashionIDs
end


-- 理发店初始化外显参数，不包含玩具
function UserData:getAvatarShopParams()
	local info = self.player:getUserBaseInfo()
	info.mountID = 0
	info.fashionIDs = self:getFashionIDs(true, true)

	return info
end

--根据消耗字符串判断是有资源支付
-- function UserData:canPayCost(costStr)
--     local splitedStr = string.split(costStr,";")
--     for _,stringToFind in pairs(splitedStr) do
--         if stringToFind then
--             local stringArray = string.split(stringToFind,"|")
--             if stringArray and #stringArray==3 then
--                 local payType=tonumber(stringArray[1])
--                 local payId=tonumber(stringArray[2])
--                 local payAmount=tonumber(stringArray[3])
--                 if payType==99 then
--                     if self:getGold()<payAmount then
--                         return false,payType
--                     end
--                 elseif payType==98 then
--                     if self:getCoin()<payAmount then
--                         return false,payType
--                     end
--                 elseif payType==1 then
--                     if not self:isItemExsit(payId) then
--                         return false,payType
--                     end
--                 else
--                 end
--             end
--         end
--     end
--     return true,0
-- end

-- 跨天刷新
function UserData:onDailyUpdate(isWeekChange)
	self.player:updateCharmLastUpdateTime()
	self.player:onDailyUpdate()

	-- 重置宝箱开启过的次数
	--[[ for k,v in pairs( self._luckBoxOpendTimesList ) do
		self._luckBoxOpendTimesList[k] = 0
	end ]]

	for k,dungeonTimes in pairs(self.dungeonTimesDict) do
		dungeonTimes.DailyTimes = dungeonTimes.DailyLimit
		if dungeonTimes.WeeklyLimit > 0 and isWeekChange then
			dungeonTimes.WeeklyTimes = dungeonTimes.WeeklyLimit
		end
	end
end

-- dataTtemp = Item/Equip/Mount/Fame/Tool/Daibi
function UserData:getNumByRenderData( dataTtemp )
	if not dataTtemp then return 0 end
	
	local hasNum = 0
	if dataTtemp.itemBagType == Enums.ItemBagType.item or dataTtemp.itemBagType == Enums.ItemBagType.equip then
		hasNum = self:getItemAmountByTid( dataTtemp:getId() )
	elseif dataTtemp.itemBagType == Enums.ItemBagType.daibi then
		hasNum = self:getDaibiValue( dataTtemp:getId() )
	else
		dump( dataTtemp, " ------------>>>>> UD:getNumByRenderData " )
		-- hasNum = -1
	end
	return hasNum
end

-- 返回宝箱信息
-- tp = Enums.BoxType
function UserData:getLuckBoxOpendTimesByType( tp )
	if self._luckBoxOpendTimesList then
		return self._luckBoxOpendTimesList[ tp ]
	end
end

-- 获得宝箱每日最大次数
-- tp = Enums.BoxType
function UserData:getLuckBoxDailyMaxNum(tp)
	local boxInfo = self:getLuckBoxOpendTimesByType(tp)
	if boxInfo and boxInfo.dayLimit then
		return tonumber(boxInfo.dayLimit)
	else
		if tp == Enums.BoxType.dungeon then
			return tonumber( S( "dungeonBoxOpenLimited", 10 ) )
		elseif tp == Enums.BoxType.pvp then
			return tonumber( S( "tourBoxOpenLimited", 10 ) )
		elseif tp == Enums.BoxType.eventBox then
			return tonumber( S( "eventBoxDailyOpenLimited", 10 ) )
		else
			return 65536
		end
	end	
end

-- 获得宝箱每周最大次数
function UserData:getLuckBoxWeeklyMaxNum(tp)
	local boxInfo = self:getLuckBoxOpendTimesByType(tp)
	if boxInfo and boxInfo.weekLimit then
		return tonumber(boxInfo.weekLimit)
	else
		if tp == Enums.BoxType.dungeon then
			return tonumber( S( "dungeonBoxWeeklyOpenLimited", 10 ) )
		elseif tp == Enums.BoxType.pvp then
			return tonumber( S( "tourBoxWeeklyOpenLimited", 10 ) )
		elseif tp == Enums.BoxType.eventBox then
			return tonumber( S( "eventBoxWeeklyOpenLimited", 10 ) )
		else
			return 65536
		end
	end	
end

-- 返回宝箱每日剩余开启次数
-- tp = Enums.BoxType
function UserData:getLuckBoxRestTimesByType( tp )
	local boxInfo = self:getLuckBoxOpendTimesByType( tp )
	local opendTimes = 0
	if boxInfo and boxInfo.dayTimes then
		opendTimes = tonumber(boxInfo.dayTimes)
	end
	local maxNum = self:getLuckBoxDailyMaxNum(tp)
	local restTimes = maxNum - opendTimes
	local weekRestTimes = self:getLuckBoxWeeklyRestTimesByType(tp)
	restTimes = math.min(restTimes, weekRestTimes) -- 要判断一下每周剩余的次数是否更小，如果更小显示更小的。
	return restTimes > 0 and restTimes or 0
end

-- 返回宝箱每周剩余开启次数
function UserData:getLuckBoxWeeklyRestTimesByType(tp)
	local boxInfo = self:getLuckBoxOpendTimesByType( tp )
	local opendTimes = 0
	if boxInfo and boxInfo.weekTimes then
		opendTimes = tonumber(boxInfo.weekTimes)
	end
	local maxNum = self:getLuckBoxWeeklyMaxNum(tp)
	local restTimes = maxNum - opendTimes
	return restTimes > 0 and restTimes or 0
end

-- 返回激活宝箱需要的点数（地城和活动是点数，竞技是星章）
function UserData:getLuckBoxLevelUpPoint(tp)
	local boxInfo = self:getLuckBoxOpendTimesByType(tp)
	if boxInfo and boxInfo.levelUpPoint and boxInfo.levelUpPoint ~= 0 then
		return tonumber(boxInfo.levelUpPoint)
	else		
		if tp == Enums.BoxType.dungeon then
			local level = self:getLevel()
			local config = GD:getDungeonBoxPointById(level)
			return config and tonumber(config.boxLimit) or 0
		elseif tp == Enums.BoxType.pvp then
			return tonumber(GD:getSystemPar("arenaBoxPointLimit", 10))
		elseif tp == Enums.BoxType.eventBox then
			return tonumber(GD:getSystemPar("eventBoxPointRequired", 10))
		end
	end
end

-- 地城/竞技/活动宝箱和点数缓存info
function UserData:setLuckBoxCache(key, old)
	self._boxCacheInfo[key] = old
end

function UserData:getLuckBoxCacheByKey(key)
	return self._boxCacheInfo[key]
end

function UserData:clearLuckBoxCacheByKey(key)
	self._boxCacheInfo[key] = nil
end

function UserData:hasDungeonLuckBoxCache()
	return self._boxCacheInfo[Enums.lootType.dungeonPoint] ~= nil
end

function UserData:hasEventLuckBoxCache()
	return self._boxCacheInfo[Enums.lootType.eventPoint] ~= nil
end

function UserData:hasArenaLuckBoxCache()
	return self._boxCacheInfo[Enums.lootType.starCount] ~= nil
end

function UserData:onlyDungeonLuckBoxChange()
	-- 获得整个宝箱(宝箱点数不变化，只有宝箱数变化)
	if self._boxCacheInfo[Enums.lootType.dungeonPoint] == nil then
		return self._boxCacheInfo[Enums.lootType.dungeonLuckBox] ~= nil
	end
end

function UserData:onlyEventLuckBoxChange()
	-- 获得整个宝箱(宝箱点数不变化，只有宝箱数变化)
	if self._boxCacheInfo[Enums.lootType.eventPoint] == nil then
		return self._boxCacheInfo[Enums.lootType.eventLuckBox] ~= nil
	end
end

function UserData:onlyArenaLuckBoxChange()
	-- 获得整个宝箱(宝箱点数不变化，只有宝箱数变化)
	if self._boxCacheInfo[Enums.lootType.starCount] == nil then
		return self._boxCacheInfo[Enums.lootType.arenaLuckBox] ~= nil
	end
end

-- 计算地城宝箱的总的副本点数缓存
function UserData:getDungeonPointCache()
	local boxNum = self._boxCacheInfo[Enums.lootType.dungeonLuckBox]
	local lastPoint = self._boxCacheInfo[Enums.lootType.dungeonPoint]
	if boxNum and lastPoint then
		return lastPoint + boxNum * self:getLuckBoxLevelUpPoint(Enums.BoxType.dungeon)
	end
end

-- 计算活动宝箱的总的活动点数缓存
function UserData:getEventPointCache()
	local boxNum = self._boxCacheInfo[Enums.lootType.eventLuckBox]
	local lastPoint = self._boxCacheInfo[Enums.lootType.eventPoint]
	if boxNum and lastPoint then
		return lastPoint + boxNum * self:getLuckBoxLevelUpPoint(Enums.BoxType.eventBox)
	end
end

-- 计算竞技宝箱的总的starCount缓存
function UserData:getStarCountCache()
	local boxNum = self._boxCacheInfo[Enums.lootType.arenaLuckBox]
	local lastPoint = self._boxCacheInfo[Enums.lootType.starCount]
	if boxNum and lastPoint then
		return lastPoint + boxNum * self:getLuckBoxLevelUpPoint(Enums.BoxType.pvp)
	end
end

-- 获取分支任务id
function UserData:getTaskBranchId(taskId)
	return self._taskBranchs[taskId]
end

function UserData:getCrystalCanBreak()
    return self.minEquipStrengthLv >= 25
end

return UserData
